diff options
-rw-r--r-- | arch/um/drivers/chan_kern.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 4e7e3cfa21f9..bce9b3427b09 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c | |||
@@ -222,15 +222,28 @@ void enable_chan(struct line *line) | |||
222 | } | 222 | } |
223 | } | 223 | } |
224 | 224 | ||
225 | /* Items are added in IRQ context, when free_irq can't be called, and | ||
226 | * removed in process context, when it can. | ||
227 | * This handles interrupt sources which disappear, and which need to | ||
228 | * be permanently disabled. This is discovered in IRQ context, but | ||
229 | * the freeing of the IRQ must be done later. | ||
230 | */ | ||
231 | static DEFINE_SPINLOCK(irqs_to_free_lock); | ||
225 | static LIST_HEAD(irqs_to_free); | 232 | static LIST_HEAD(irqs_to_free); |
226 | 233 | ||
227 | void free_irqs(void) | 234 | void free_irqs(void) |
228 | { | 235 | { |
229 | struct chan *chan; | 236 | struct chan *chan; |
237 | LIST_HEAD(list); | ||
238 | struct list_head *ele; | ||
239 | |||
240 | spin_lock_irq(&irqs_to_free_lock); | ||
241 | list_splice_init(&irqs_to_free, &list); | ||
242 | INIT_LIST_HEAD(&irqs_to_free); | ||
243 | spin_unlock_irq(&irqs_to_free_lock); | ||
230 | 244 | ||
231 | while(!list_empty(&irqs_to_free)){ | 245 | list_for_each(ele, &list){ |
232 | chan = list_entry(irqs_to_free.next, struct chan, free_list); | 246 | chan = list_entry(ele, struct chan, free_list); |
233 | list_del(&chan->free_list); | ||
234 | 247 | ||
235 | if(chan->input) | 248 | if(chan->input) |
236 | free_irq(chan->line->driver->read_irq, chan); | 249 | free_irq(chan->line->driver->read_irq, chan); |
@@ -246,7 +259,9 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) | |||
246 | return; | 259 | return; |
247 | 260 | ||
248 | if(delay_free_irq){ | 261 | if(delay_free_irq){ |
262 | spin_lock_irq(&irqs_to_free_lock); | ||
249 | list_add(&chan->free_list, &irqs_to_free); | 263 | list_add(&chan->free_list, &irqs_to_free); |
264 | spin_unlock_irq(&irqs_to_free_lock); | ||
250 | } | 265 | } |
251 | else { | 266 | else { |
252 | if(chan->input) | 267 | if(chan->input) |