diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2013-02-06 04:23:39 -0500 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-03-04 04:41:04 -0500 |
commit | 96b14536d935848cffd904f583f67c66169002d8 (patch) | |
tree | 87d6be1ed35f1d12f0da33cc88a533bc0fd1afd9 | |
parent | 84ec96a6150477b9509664557bc6ad4eaa21f72a (diff) |
virtio-ccw: virtio-ccw adapter interrupt support.
Implement the new CCW_CMD_SET_IND_ADAPTER command and try to enable
adapter interrupts for every device on the first startup. If the host
does not support adapter interrupts, fall back to normal I/O interrupts.
virtio-ccw adapter interrupts use the same isc as normal I/O subchannels
and share a summary indicator for all devices sharing the same indicator
area.
Indicator bits for the individual virtqueues may be contained in the same
indicator area for different devices.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/irq.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/irq.c | 1 | ||||
-rw-r--r-- | drivers/s390/kvm/virtio_ccw.c | 278 |
3 files changed, 270 insertions, 10 deletions
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 5f8bcc5fe423..35f0faab5361 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h | |||
@@ -53,6 +53,7 @@ enum interruption_class { | |||
53 | IRQIO_PCI, | 53 | IRQIO_PCI, |
54 | IRQIO_MSI, | 54 | IRQIO_MSI, |
55 | IRQIO_VIR, | 55 | IRQIO_VIR, |
56 | IRQIO_VAI, | ||
56 | NMI_NMI, | 57 | NMI_NMI, |
57 | CPU_RST, | 58 | CPU_RST, |
58 | NR_ARCH_IRQS | 59 | NR_ARCH_IRQS |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index bb27a262c44a..c288ef7e47b4 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -84,6 +84,7 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = { | |||
84 | [IRQIO_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, | 84 | [IRQIO_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, |
85 | [IRQIO_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" }, | 85 | [IRQIO_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" }, |
86 | [IRQIO_VIR] = {.name = "VIR", .desc = "[I/O] Virtual I/O Devices"}, | 86 | [IRQIO_VIR] = {.name = "VIR", .desc = "[I/O] Virtual I/O Devices"}, |
87 | [IRQIO_VAI] = {.name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"}, | ||
87 | [NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"}, | 88 | [NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"}, |
88 | [CPU_RST] = {.name = "RST", .desc = "[CPU] CPU Restart"}, | 89 | [CPU_RST] = {.name = "RST", .desc = "[CPU] CPU Restart"}, |
89 | }; | 90 | }; |
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c index 413c6304d511..6a2b5fdcd552 100644 --- a/drivers/s390/kvm/virtio_ccw.c +++ b/drivers/s390/kvm/virtio_ccw.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ccw based virtio transport | 2 | * ccw based virtio transport |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2012 | 4 | * Copyright IBM Corp. 2012, 2014 |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License (version 2 only) | 7 | * it under the terms of the GNU General Public License (version 2 only) |
@@ -32,6 +32,8 @@ | |||
32 | #include <asm/cio.h> | 32 | #include <asm/cio.h> |
33 | #include <asm/ccwdev.h> | 33 | #include <asm/ccwdev.h> |
34 | #include <asm/virtio-ccw.h> | 34 | #include <asm/virtio-ccw.h> |
35 | #include <asm/isc.h> | ||
36 | #include <asm/airq.h> | ||
35 | 37 | ||
36 | /* | 38 | /* |
37 | * virtio related functions | 39 | * virtio related functions |
@@ -58,6 +60,8 @@ struct virtio_ccw_device { | |||
58 | unsigned long indicators; | 60 | unsigned long indicators; |
59 | unsigned long indicators2; | 61 | unsigned long indicators2; |
60 | struct vq_config_block *config_block; | 62 | struct vq_config_block *config_block; |
63 | bool is_thinint; | ||
64 | void *airq_info; | ||
61 | }; | 65 | }; |
62 | 66 | ||
63 | struct vq_info_block { | 67 | struct vq_info_block { |
@@ -72,15 +76,38 @@ struct virtio_feature_desc { | |||
72 | __u8 index; | 76 | __u8 index; |
73 | } __packed; | 77 | } __packed; |
74 | 78 | ||
79 | struct virtio_thinint_area { | ||
80 | unsigned long summary_indicator; | ||
81 | unsigned long indicator; | ||
82 | u64 bit_nr; | ||
83 | u8 isc; | ||
84 | } __packed; | ||
85 | |||
75 | struct virtio_ccw_vq_info { | 86 | struct virtio_ccw_vq_info { |
76 | struct virtqueue *vq; | 87 | struct virtqueue *vq; |
77 | int num; | 88 | int num; |
78 | void *queue; | 89 | void *queue; |
79 | struct vq_info_block *info_block; | 90 | struct vq_info_block *info_block; |
91 | int bit_nr; | ||
80 | struct list_head node; | 92 | struct list_head node; |
81 | long cookie; | 93 | long cookie; |
82 | }; | 94 | }; |
83 | 95 | ||
96 | #define VIRTIO_AIRQ_ISC IO_SCH_ISC /* inherit from subchannel */ | ||
97 | |||
98 | #define VIRTIO_IV_BITS (L1_CACHE_BYTES * 8) | ||
99 | #define MAX_AIRQ_AREAS 20 | ||
100 | |||
101 | static int virtio_ccw_use_airq = 1; | ||
102 | |||
103 | struct airq_info { | ||
104 | rwlock_t lock; | ||
105 | u8 summary_indicator; | ||
106 | struct airq_struct airq; | ||
107 | struct airq_iv *aiv; | ||
108 | }; | ||
109 | static struct airq_info *airq_areas[MAX_AIRQ_AREAS]; | ||
110 | |||
84 | #define CCW_CMD_SET_VQ 0x13 | 111 | #define CCW_CMD_SET_VQ 0x13 |
85 | #define CCW_CMD_VDEV_RESET 0x33 | 112 | #define CCW_CMD_VDEV_RESET 0x33 |
86 | #define CCW_CMD_SET_IND 0x43 | 113 | #define CCW_CMD_SET_IND 0x43 |
@@ -91,6 +118,7 @@ struct virtio_ccw_vq_info { | |||
91 | #define CCW_CMD_WRITE_CONF 0x21 | 118 | #define CCW_CMD_WRITE_CONF 0x21 |
92 | #define CCW_CMD_WRITE_STATUS 0x31 | 119 | #define CCW_CMD_WRITE_STATUS 0x31 |
93 | #define CCW_CMD_READ_VQ_CONF 0x32 | 120 | #define CCW_CMD_READ_VQ_CONF 0x32 |
121 | #define CCW_CMD_SET_IND_ADAPTER 0x73 | ||
94 | 122 | ||
95 | #define VIRTIO_CCW_DOING_SET_VQ 0x00010000 | 123 | #define VIRTIO_CCW_DOING_SET_VQ 0x00010000 |
96 | #define VIRTIO_CCW_DOING_RESET 0x00040000 | 124 | #define VIRTIO_CCW_DOING_RESET 0x00040000 |
@@ -102,6 +130,7 @@ struct virtio_ccw_vq_info { | |||
102 | #define VIRTIO_CCW_DOING_SET_IND 0x01000000 | 130 | #define VIRTIO_CCW_DOING_SET_IND 0x01000000 |
103 | #define VIRTIO_CCW_DOING_READ_VQ_CONF 0x02000000 | 131 | #define VIRTIO_CCW_DOING_READ_VQ_CONF 0x02000000 |
104 | #define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000 | 132 | #define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000 |
133 | #define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000 | ||
105 | #define VIRTIO_CCW_INTPARM_MASK 0xffff0000 | 134 | #define VIRTIO_CCW_INTPARM_MASK 0xffff0000 |
106 | 135 | ||
107 | static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev) | 136 | static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev) |
@@ -109,6 +138,125 @@ static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev) | |||
109 | return container_of(vdev, struct virtio_ccw_device, vdev); | 138 | return container_of(vdev, struct virtio_ccw_device, vdev); |
110 | } | 139 | } |
111 | 140 | ||
141 | static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info) | ||
142 | { | ||
143 | unsigned long i, flags; | ||
144 | |||
145 | write_lock_irqsave(&info->lock, flags); | ||
146 | for (i = 0; i < airq_iv_end(info->aiv); i++) { | ||
147 | if (vq == (void *)airq_iv_get_ptr(info->aiv, i)) { | ||
148 | airq_iv_free_bit(info->aiv, i); | ||
149 | airq_iv_set_ptr(info->aiv, i, 0); | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | write_unlock_irqrestore(&info->lock, flags); | ||
154 | } | ||
155 | |||
156 | static void virtio_airq_handler(struct airq_struct *airq) | ||
157 | { | ||
158 | struct airq_info *info = container_of(airq, struct airq_info, airq); | ||
159 | unsigned long ai; | ||
160 | |||
161 | inc_irq_stat(IRQIO_VAI); | ||
162 | read_lock(&info->lock); | ||
163 | /* Walk through indicators field, summary indicator active. */ | ||
164 | for (ai = 0;;) { | ||
165 | ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv)); | ||
166 | if (ai == -1UL) | ||
167 | break; | ||
168 | vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai)); | ||
169 | } | ||
170 | info->summary_indicator = 0; | ||
171 | smp_wmb(); | ||
172 | /* Walk through indicators field, summary indicator not active. */ | ||
173 | for (ai = 0;;) { | ||
174 | ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv)); | ||
175 | if (ai == -1UL) | ||
176 | break; | ||
177 | vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai)); | ||
178 | } | ||
179 | read_unlock(&info->lock); | ||
180 | } | ||
181 | |||
182 | static struct airq_info *new_airq_info(void) | ||
183 | { | ||
184 | struct airq_info *info; | ||
185 | int rc; | ||
186 | |||
187 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
188 | if (!info) | ||
189 | return NULL; | ||
190 | rwlock_init(&info->lock); | ||
191 | info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR); | ||
192 | if (!info->aiv) { | ||
193 | kfree(info); | ||
194 | return NULL; | ||
195 | } | ||
196 | info->airq.handler = virtio_airq_handler; | ||
197 | info->airq.lsi_ptr = &info->summary_indicator; | ||
198 | info->airq.lsi_mask = 0xff; | ||
199 | info->airq.isc = VIRTIO_AIRQ_ISC; | ||
200 | rc = register_adapter_interrupt(&info->airq); | ||
201 | if (rc) { | ||
202 | airq_iv_release(info->aiv); | ||
203 | kfree(info); | ||
204 | return NULL; | ||
205 | } | ||
206 | return info; | ||
207 | } | ||
208 | |||
209 | static void destroy_airq_info(struct airq_info *info) | ||
210 | { | ||
211 | if (!info) | ||
212 | return; | ||
213 | |||
214 | unregister_adapter_interrupt(&info->airq); | ||
215 | airq_iv_release(info->aiv); | ||
216 | kfree(info); | ||
217 | } | ||
218 | |||
219 | static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs, | ||
220 | u64 *first, void **airq_info) | ||
221 | { | ||
222 | int i, j; | ||
223 | struct airq_info *info; | ||
224 | unsigned long indicator_addr = 0; | ||
225 | unsigned long bit, flags; | ||
226 | |||
227 | for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) { | ||
228 | if (!airq_areas[i]) | ||
229 | airq_areas[i] = new_airq_info(); | ||
230 | info = airq_areas[i]; | ||
231 | if (!info) | ||
232 | return 0; | ||
233 | write_lock_irqsave(&info->lock, flags); | ||
234 | bit = airq_iv_alloc(info->aiv, nvqs); | ||
235 | if (bit == -1UL) { | ||
236 | /* Not enough vacancies. */ | ||
237 | write_unlock_irqrestore(&info->lock, flags); | ||
238 | continue; | ||
239 | } | ||
240 | *first = bit; | ||
241 | *airq_info = info; | ||
242 | indicator_addr = (unsigned long)info->aiv->vector; | ||
243 | for (j = 0; j < nvqs; j++) { | ||
244 | airq_iv_set_ptr(info->aiv, bit + j, | ||
245 | (unsigned long)vqs[j]); | ||
246 | } | ||
247 | write_unlock_irqrestore(&info->lock, flags); | ||
248 | } | ||
249 | return indicator_addr; | ||
250 | } | ||
251 | |||
252 | static void virtio_ccw_drop_indicators(struct virtio_ccw_device *vcdev) | ||
253 | { | ||
254 | struct virtio_ccw_vq_info *info; | ||
255 | |||
256 | list_for_each_entry(info, &vcdev->virtqueues, node) | ||
257 | drop_airq_indicator(info->vq, vcdev->airq_info); | ||
258 | } | ||
259 | |||
112 | static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag) | 260 | static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag) |
113 | { | 261 | { |
114 | unsigned long flags; | 262 | unsigned long flags; |
@@ -145,6 +293,51 @@ static int ccw_io_helper(struct virtio_ccw_device *vcdev, | |||
145 | return ret ? ret : vcdev->err; | 293 | return ret ? ret : vcdev->err; |
146 | } | 294 | } |
147 | 295 | ||
296 | static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, | ||
297 | struct ccw1 *ccw) | ||
298 | { | ||
299 | int ret; | ||
300 | unsigned long *indicatorp = NULL; | ||
301 | struct virtio_thinint_area *thinint_area = NULL; | ||
302 | struct airq_info *airq_info = vcdev->airq_info; | ||
303 | |||
304 | if (vcdev->is_thinint) { | ||
305 | thinint_area = kzalloc(sizeof(*thinint_area), | ||
306 | GFP_DMA | GFP_KERNEL); | ||
307 | if (!thinint_area) | ||
308 | return; | ||
309 | thinint_area->summary_indicator = | ||
310 | (unsigned long) &airq_info->summary_indicator; | ||
311 | thinint_area->isc = VIRTIO_AIRQ_ISC; | ||
312 | ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER; | ||
313 | ccw->count = sizeof(*thinint_area); | ||
314 | ccw->cda = (__u32)(unsigned long) thinint_area; | ||
315 | } else { | ||
316 | indicatorp = kmalloc(sizeof(&vcdev->indicators), | ||
317 | GFP_DMA | GFP_KERNEL); | ||
318 | if (!indicatorp) | ||
319 | return; | ||
320 | *indicatorp = 0; | ||
321 | ccw->cmd_code = CCW_CMD_SET_IND; | ||
322 | ccw->count = sizeof(vcdev->indicators); | ||
323 | ccw->cda = (__u32)(unsigned long) indicatorp; | ||
324 | } | ||
325 | /* Deregister indicators from host. */ | ||
326 | vcdev->indicators = 0; | ||
327 | ccw->flags = 0; | ||
328 | ret = ccw_io_helper(vcdev, ccw, | ||
329 | vcdev->is_thinint ? | ||
330 | VIRTIO_CCW_DOING_SET_IND_ADAPTER : | ||
331 | VIRTIO_CCW_DOING_SET_IND); | ||
332 | if (ret && (ret != -ENODEV)) | ||
333 | dev_info(&vcdev->cdev->dev, | ||
334 | "Failed to deregister indicators (%d)\n", ret); | ||
335 | else if (vcdev->is_thinint) | ||
336 | virtio_ccw_drop_indicators(vcdev); | ||
337 | kfree(indicatorp); | ||
338 | kfree(thinint_area); | ||
339 | } | ||
340 | |||
148 | static inline long do_kvm_notify(struct subchannel_id schid, | 341 | static inline long do_kvm_notify(struct subchannel_id schid, |
149 | unsigned long queue_index, | 342 | unsigned long queue_index, |
150 | long cookie) | 343 | long cookie) |
@@ -232,11 +425,13 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev) | |||
232 | { | 425 | { |
233 | struct virtqueue *vq, *n; | 426 | struct virtqueue *vq, *n; |
234 | struct ccw1 *ccw; | 427 | struct ccw1 *ccw; |
428 | struct virtio_ccw_device *vcdev = to_vc_device(vdev); | ||
235 | 429 | ||
236 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); | 430 | ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); |
237 | if (!ccw) | 431 | if (!ccw) |
238 | return; | 432 | return; |
239 | 433 | ||
434 | virtio_ccw_drop_indicator(vcdev, ccw); | ||
240 | 435 | ||
241 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | 436 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) |
242 | virtio_ccw_del_vq(vq, ccw); | 437 | virtio_ccw_del_vq(vq, ccw); |
@@ -326,6 +521,54 @@ out_err: | |||
326 | return ERR_PTR(err); | 521 | return ERR_PTR(err); |
327 | } | 522 | } |
328 | 523 | ||
524 | static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev, | ||
525 | struct virtqueue *vqs[], int nvqs, | ||
526 | struct ccw1 *ccw) | ||
527 | { | ||
528 | int ret; | ||
529 | struct virtio_thinint_area *thinint_area = NULL; | ||
530 | struct airq_info *info; | ||
531 | |||
532 | thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL); | ||
533 | if (!thinint_area) { | ||
534 | ret = -ENOMEM; | ||
535 | goto out; | ||
536 | } | ||
537 | /* Try to get an indicator. */ | ||
538 | thinint_area->indicator = get_airq_indicator(vqs, nvqs, | ||
539 | &thinint_area->bit_nr, | ||
540 | &vcdev->airq_info); | ||
541 | if (!thinint_area->indicator) { | ||
542 | ret = -ENOSPC; | ||
543 | goto out; | ||
544 | } | ||
545 | info = vcdev->airq_info; | ||
546 | thinint_area->summary_indicator = | ||
547 | (unsigned long) &info->summary_indicator; | ||
548 | thinint_area->isc = VIRTIO_AIRQ_ISC; | ||
549 | ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER; | ||
550 | ccw->flags = CCW_FLAG_SLI; | ||
551 | ccw->count = sizeof(*thinint_area); | ||
552 | ccw->cda = (__u32)(unsigned long)thinint_area; | ||
553 | ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER); | ||
554 | if (ret) { | ||
555 | if (ret == -EOPNOTSUPP) { | ||
556 | /* | ||
557 | * The host does not support adapter interrupts | ||
558 | * for virtio-ccw, stop trying. | ||
559 | */ | ||
560 | virtio_ccw_use_airq = 0; | ||
561 | pr_info("Adapter interrupts unsupported on host\n"); | ||
562 | } else | ||
563 | dev_warn(&vcdev->cdev->dev, | ||
564 | "enabling adapter interrupts = %d\n", ret); | ||
565 | virtio_ccw_drop_indicators(vcdev); | ||
566 | } | ||
567 | out: | ||
568 | kfree(thinint_area); | ||
569 | return ret; | ||
570 | } | ||
571 | |||
329 | static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, | 572 | static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, |
330 | struct virtqueue *vqs[], | 573 | struct virtqueue *vqs[], |
331 | vq_callback_t *callbacks[], | 574 | vq_callback_t *callbacks[], |
@@ -355,15 +598,23 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, | |||
355 | if (!indicatorp) | 598 | if (!indicatorp) |
356 | goto out; | 599 | goto out; |
357 | *indicatorp = (unsigned long) &vcdev->indicators; | 600 | *indicatorp = (unsigned long) &vcdev->indicators; |
358 | /* Register queue indicators with host. */ | 601 | if (vcdev->is_thinint) { |
359 | vcdev->indicators = 0; | 602 | ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw); |
360 | ccw->cmd_code = CCW_CMD_SET_IND; | 603 | if (ret) |
361 | ccw->flags = 0; | 604 | /* no error, just fall back to legacy interrupts */ |
362 | ccw->count = sizeof(vcdev->indicators); | 605 | vcdev->is_thinint = 0; |
363 | ccw->cda = (__u32)(unsigned long) indicatorp; | 606 | } |
364 | ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND); | 607 | if (!vcdev->is_thinint) { |
365 | if (ret) | 608 | /* Register queue indicators with host. */ |
366 | goto out; | 609 | vcdev->indicators = 0; |
610 | ccw->cmd_code = CCW_CMD_SET_IND; | ||
611 | ccw->flags = 0; | ||
612 | ccw->count = sizeof(vcdev->indicators); | ||
613 | ccw->cda = (__u32)(unsigned long) indicatorp; | ||
614 | ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND); | ||
615 | if (ret) | ||
616 | goto out; | ||
617 | } | ||
367 | /* Register indicators2 with host for config changes */ | 618 | /* Register indicators2 with host for config changes */ |
368 | *indicatorp = (unsigned long) &vcdev->indicators2; | 619 | *indicatorp = (unsigned long) &vcdev->indicators2; |
369 | vcdev->indicators2 = 0; | 620 | vcdev->indicators2 = 0; |
@@ -665,6 +916,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev, | |||
665 | case VIRTIO_CCW_DOING_SET_CONF_IND: | 916 | case VIRTIO_CCW_DOING_SET_CONF_IND: |
666 | case VIRTIO_CCW_DOING_RESET: | 917 | case VIRTIO_CCW_DOING_RESET: |
667 | case VIRTIO_CCW_DOING_READ_VQ_CONF: | 918 | case VIRTIO_CCW_DOING_READ_VQ_CONF: |
919 | case VIRTIO_CCW_DOING_SET_IND_ADAPTER: | ||
668 | vcdev->curr_io &= ~activity; | 920 | vcdev->curr_io &= ~activity; |
669 | wake_up(&vcdev->wait_q); | 921 | wake_up(&vcdev->wait_q); |
670 | break; | 922 | break; |
@@ -795,6 +1047,8 @@ static int virtio_ccw_online(struct ccw_device *cdev) | |||
795 | goto out_free; | 1047 | goto out_free; |
796 | } | 1048 | } |
797 | 1049 | ||
1050 | vcdev->is_thinint = virtio_ccw_use_airq; /* at least try */ | ||
1051 | |||
798 | vcdev->vdev.dev.parent = &cdev->dev; | 1052 | vcdev->vdev.dev.parent = &cdev->dev; |
799 | vcdev->vdev.dev.release = virtio_ccw_release_dev; | 1053 | vcdev->vdev.dev.release = virtio_ccw_release_dev; |
800 | vcdev->vdev.config = &virtio_ccw_config_ops; | 1054 | vcdev->vdev.config = &virtio_ccw_config_ops; |
@@ -956,6 +1210,10 @@ module_init(virtio_ccw_init); | |||
956 | 1210 | ||
957 | static void __exit virtio_ccw_exit(void) | 1211 | static void __exit virtio_ccw_exit(void) |
958 | { | 1212 | { |
1213 | int i; | ||
1214 | |||
959 | ccw_driver_unregister(&virtio_ccw_driver); | 1215 | ccw_driver_unregister(&virtio_ccw_driver); |
1216 | for (i = 0; i < MAX_AIRQ_AREAS; i++) | ||
1217 | destroy_airq_info(airq_areas[i]); | ||
960 | } | 1218 | } |
961 | module_exit(virtio_ccw_exit); | 1219 | module_exit(virtio_ccw_exit); |