diff options
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r-- | kernel/irq/manage.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0a7840aeb0f..d6c4adc2804 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -620,8 +620,9 @@ static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id) | |||
620 | 620 | ||
621 | static int irq_wait_for_interrupt(struct irqaction *action) | 621 | static int irq_wait_for_interrupt(struct irqaction *action) |
622 | { | 622 | { |
623 | set_current_state(TASK_INTERRUPTIBLE); | ||
624 | |||
623 | while (!kthread_should_stop()) { | 625 | while (!kthread_should_stop()) { |
624 | set_current_state(TASK_INTERRUPTIBLE); | ||
625 | 626 | ||
626 | if (test_and_clear_bit(IRQTF_RUNTHREAD, | 627 | if (test_and_clear_bit(IRQTF_RUNTHREAD, |
627 | &action->thread_flags)) { | 628 | &action->thread_flags)) { |
@@ -629,7 +630,9 @@ static int irq_wait_for_interrupt(struct irqaction *action) | |||
629 | return 0; | 630 | return 0; |
630 | } | 631 | } |
631 | schedule(); | 632 | schedule(); |
633 | set_current_state(TASK_INTERRUPTIBLE); | ||
632 | } | 634 | } |
635 | __set_current_state(TASK_RUNNING); | ||
633 | return -1; | 636 | return -1; |
634 | } | 637 | } |
635 | 638 | ||
@@ -883,6 +886,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
883 | 886 | ||
884 | if (desc->irq_data.chip == &no_irq_chip) | 887 | if (desc->irq_data.chip == &no_irq_chip) |
885 | return -ENOSYS; | 888 | return -ENOSYS; |
889 | if (!try_module_get(desc->owner)) | ||
890 | return -ENODEV; | ||
886 | /* | 891 | /* |
887 | * Some drivers like serial.c use request_irq() heavily, | 892 | * Some drivers like serial.c use request_irq() heavily, |
888 | * so we have to be careful not to interfere with a | 893 | * so we have to be careful not to interfere with a |
@@ -906,8 +911,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
906 | */ | 911 | */ |
907 | nested = irq_settings_is_nested_thread(desc); | 912 | nested = irq_settings_is_nested_thread(desc); |
908 | if (nested) { | 913 | if (nested) { |
909 | if (!new->thread_fn) | 914 | if (!new->thread_fn) { |
910 | return -EINVAL; | 915 | ret = -EINVAL; |
916 | goto out_mput; | ||
917 | } | ||
911 | /* | 918 | /* |
912 | * Replace the primary handler which was provided from | 919 | * Replace the primary handler which was provided from |
913 | * the driver for non nested interrupt handling by the | 920 | * the driver for non nested interrupt handling by the |
@@ -929,8 +936,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
929 | 936 | ||
930 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, | 937 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, |
931 | new->name); | 938 | new->name); |
932 | if (IS_ERR(t)) | 939 | if (IS_ERR(t)) { |
933 | return PTR_ERR(t); | 940 | ret = PTR_ERR(t); |
941 | goto out_mput; | ||
942 | } | ||
934 | /* | 943 | /* |
935 | * We keep the reference to the task struct even if | 944 | * We keep the reference to the task struct even if |
936 | * the thread dies to avoid that the interrupt code | 945 | * the thread dies to avoid that the interrupt code |
@@ -1095,6 +1104,8 @@ out_thread: | |||
1095 | kthread_stop(t); | 1104 | kthread_stop(t); |
1096 | put_task_struct(t); | 1105 | put_task_struct(t); |
1097 | } | 1106 | } |
1107 | out_mput: | ||
1108 | module_put(desc->owner); | ||
1098 | return ret; | 1109 | return ret; |
1099 | } | 1110 | } |
1100 | 1111 | ||
@@ -1203,6 +1214,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
1203 | put_task_struct(action->thread); | 1214 | put_task_struct(action->thread); |
1204 | } | 1215 | } |
1205 | 1216 | ||
1217 | module_put(desc->owner); | ||
1206 | return action; | 1218 | return action; |
1207 | } | 1219 | } |
1208 | 1220 | ||