]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.arch/s390-11-07-qdio_kill_tasklets.patch
Reenabled linux-xen, added patches for Xen Kernel Version 2.6.27.31,
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.arch / s390-11-07-qdio_kill_tasklets.patch
1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: qdio: proper kill of qdio tasklets
3 References: bnc#484767,LTC#52206
4
5 Symptom: kernel BUG at kernel/softirq.c:392!
6 Problem: The queue tasklets were stopped with tasklet_disable. Although
7 tasklet_disable prevents the tasklet from beeing executed it is
8 still possible that a tasklet is scheduled on a CPU at that point.
9 A following qdio_establish calls tasklet_init which clears the
10 tasklet count and the tasklet state leading to the oops.
11 Solution: Use tasklet_kill instead of tasklet_disbale. Since
12 tasklet_schedule must not be called after tasklet_kill use the
13 QDIO_IRQ_STATE_STOPPED to inidicate that a queue is going down
14 and prevent further tasklet schedules in that case.
15
16 Acked-by: John Jolly <jjolly@suse.de>
17 ---
18 drivers/s390/cio/qdio_main.c | 35 ++++++++++++++++++++++++-----------
19 drivers/s390/cio/qdio_thinint.c | 8 ++++----
20 2 files changed, 28 insertions(+), 15 deletions(-)
21
22 Index: linux-sles11/drivers/s390/cio/qdio_main.c
23 ===================================================================
24 --- linux-sles11.orig/drivers/s390/cio/qdio_main.c
25 +++ linux-sles11/drivers/s390/cio/qdio_main.c
26 @@ -760,21 +760,17 @@ static void __qdio_outbound_processing(s
27 if (qdio_outbound_q_moved(q))
28 qdio_kick_outbound_handler(q);
29
30 - if (queue_type(q) == QDIO_ZFCP_QFMT) {
31 + if (queue_type(q) == QDIO_ZFCP_QFMT)
32 if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
33 - tasklet_schedule(&q->tasklet);
34 - return;
35 - }
36 + goto sched;
37
38 /* bail out for HiperSockets unicast queues */
39 if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q))
40 return;
41
42 if ((queue_type(q) == QDIO_IQDIO_QFMT) &&
43 - (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) {
44 - tasklet_schedule(&q->tasklet);
45 - return;
46 - }
47 + (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL)
48 + goto sched;
49
50 if (q->u.out.pci_out_enabled)
51 return;
52 @@ -792,6 +788,12 @@ static void __qdio_outbound_processing(s
53 qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer);
54 }
55 }
56 + return;
57 +
58 +sched:
59 + if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
60 + return;
61 + tasklet_schedule(&q->tasklet);
62 }
63
64 /* outbound tasklet */
65 @@ -804,6 +806,9 @@ void qdio_outbound_processing(unsigned l
66 void qdio_outbound_timer(unsigned long data)
67 {
68 struct qdio_q *q = (struct qdio_q *)data;
69 +
70 + if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
71 + return;
72 tasklet_schedule(&q->tasklet);
73 }
74
75 @@ -845,6 +850,9 @@ static void qdio_int_handler_pci(struct
76 int i;
77 struct qdio_q *q;
78
79 + if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
80 + return;
81 +
82 qdio_perf_stat_inc(&perf_stats.pci_int);
83
84 for_each_input_queue(irq_ptr, q, i)
85 @@ -1072,11 +1080,11 @@ static void qdio_shutdown_queues(struct
86 int i;
87
88 for_each_input_queue(irq_ptr, q, i)
89 - tasklet_disable(&q->tasklet);
90 + tasklet_kill(&q->tasklet);
91
92 for_each_output_queue(irq_ptr, q, i) {
93 - tasklet_disable(&q->tasklet);
94 del_timer(&q->u.out.timer);
95 + tasklet_kill(&q->tasklet);
96 }
97 }
98
99 @@ -1107,6 +1115,12 @@ int qdio_shutdown(struct ccw_device *cde
100 return 0;
101 }
102
103 + /*
104 + * Indicate that the device is going down. Scheduling the queue
105 + * tasklets is forbidden from here on.
106 + */
107 + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
108 +
109 tiqdio_remove_input_queues(irq_ptr);
110 qdio_shutdown_queues(cdev);
111 qdio_shutdown_debug_entries(irq_ptr, cdev);
112 @@ -1526,7 +1540,6 @@ static int handle_outbound(struct qdio_q
113 qdio_perf_stat_inc(&perf_stats.fast_requeue);
114 }
115 out:
116 - /* Fixme: could wait forever if called from process context */
117 tasklet_schedule(&q->tasklet);
118 return rc;
119 }
120 Index: linux-sles11/drivers/s390/cio/qdio_thinint.c
121 ===================================================================
122 --- linux-sles11.orig/drivers/s390/cio/qdio_thinint.c
123 +++ linux-sles11/drivers/s390/cio/qdio_thinint.c
124 @@ -101,7 +101,6 @@ void tiqdio_add_input_queues(struct qdio
125 list_add_rcu(&q->entry, &tiq_list);
126 mutex_unlock(&tiq_list_lock);
127 xchg(irq_ptr->dsci, 1);
128 - tasklet_schedule(&tiqdio_tasklet);
129 }
130
131 /*
132 @@ -159,7 +158,6 @@ static void __tiqdio_inbound_processing(
133 */
134 qdio_check_outbound_after_thinint(q);
135
136 -again:
137 if (!qdio_inbound_q_moved(q))
138 return;
139
140 @@ -167,7 +165,8 @@ again:
141
142 if (!tiqdio_inbound_q_done(q)) {
143 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop);
144 - goto again;
145 + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
146 + tasklet_schedule(&q->tasklet);
147 }
148
149 qdio_stop_polling(q);
150 @@ -177,7 +176,8 @@ again:
151 */
152 if (!tiqdio_inbound_q_done(q)) {
153 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2);
154 - goto again;
155 + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
156 + tasklet_schedule(&q->tasklet);
157 }
158 }
159