diff options
| -rw-r--r-- | kernel/irq/internals.h | 5 | ||||
| -rw-r--r-- | kernel/irq/pm.c | 3 | ||||
| -rw-r--r-- | kernel/irq/proc.c | 2 | ||||
| -rw-r--r-- | kernel/time/timer.c | 22 |
4 files changed, 27 insertions, 5 deletions
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 05c2188271b8..fcab63c66905 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -199,6 +199,11 @@ static inline int irq_desc_get_node(struct irq_desc *desc) | |||
| 199 | return irq_common_data_get_node(&desc->irq_common_data); | 199 | return irq_common_data_get_node(&desc->irq_common_data); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | static inline int irq_desc_is_chained(struct irq_desc *desc) | ||
| 203 | { | ||
| 204 | return (desc->action && desc->action == &chained_action); | ||
| 205 | } | ||
| 206 | |||
| 202 | #ifdef CONFIG_PM_SLEEP | 207 | #ifdef CONFIG_PM_SLEEP |
| 203 | bool irq_pm_check_wakeup(struct irq_desc *desc); | 208 | bool irq_pm_check_wakeup(struct irq_desc *desc); |
| 204 | void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); | 209 | void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); |
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index e80c4400118a..cea1de0161f1 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c | |||
| @@ -70,7 +70,8 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) | |||
| 70 | 70 | ||
| 71 | static bool suspend_device_irq(struct irq_desc *desc) | 71 | static bool suspend_device_irq(struct irq_desc *desc) |
| 72 | { | 72 | { |
| 73 | if (!desc->action || desc->no_suspend_depth) | 73 | if (!desc->action || irq_desc_is_chained(desc) || |
| 74 | desc->no_suspend_depth) | ||
| 74 | return false; | 75 | return false; |
| 75 | 76 | ||
| 76 | if (irqd_is_wakeup_set(&desc->irq_data)) { | 77 | if (irqd_is_wakeup_set(&desc->irq_data)) { |
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index a916cf144b65..a2c02fd5d6d0 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
| @@ -475,7 +475,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
| 475 | for_each_online_cpu(j) | 475 | for_each_online_cpu(j) |
| 476 | any_count |= kstat_irqs_cpu(i, j); | 476 | any_count |= kstat_irqs_cpu(i, j); |
| 477 | action = desc->action; | 477 | action = desc->action; |
| 478 | if ((!action || action == &chained_action) && !any_count) | 478 | if ((!action || irq_desc_is_chained(desc)) && !any_count) |
| 479 | goto out; | 479 | goto out; |
| 480 | 480 | ||
| 481 | seq_printf(p, "%*d: ", prec, i); | 481 | seq_printf(p, "%*d: ", prec, i); |
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 74591ba9474f..bbc5d1114583 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c | |||
| @@ -977,13 +977,29 @@ EXPORT_SYMBOL(add_timer); | |||
| 977 | */ | 977 | */ |
| 978 | void add_timer_on(struct timer_list *timer, int cpu) | 978 | void add_timer_on(struct timer_list *timer, int cpu) |
| 979 | { | 979 | { |
| 980 | struct tvec_base *base = per_cpu_ptr(&tvec_bases, cpu); | 980 | struct tvec_base *new_base = per_cpu_ptr(&tvec_bases, cpu); |
| 981 | struct tvec_base *base; | ||
| 981 | unsigned long flags; | 982 | unsigned long flags; |
| 982 | 983 | ||
| 983 | timer_stats_timer_set_start_info(timer); | 984 | timer_stats_timer_set_start_info(timer); |
| 984 | BUG_ON(timer_pending(timer) || !timer->function); | 985 | BUG_ON(timer_pending(timer) || !timer->function); |
| 985 | spin_lock_irqsave(&base->lock, flags); | 986 | |
| 986 | timer->flags = (timer->flags & ~TIMER_BASEMASK) | cpu; | 987 | /* |
| 988 | * If @timer was on a different CPU, it should be migrated with the | ||
| 989 | * old base locked to prevent other operations proceeding with the | ||
| 990 | * wrong base locked. See lock_timer_base(). | ||
| 991 | */ | ||
| 992 | base = lock_timer_base(timer, &flags); | ||
| 993 | if (base != new_base) { | ||
| 994 | timer->flags |= TIMER_MIGRATING; | ||
| 995 | |||
| 996 | spin_unlock(&base->lock); | ||
| 997 | base = new_base; | ||
| 998 | spin_lock(&base->lock); | ||
| 999 | WRITE_ONCE(timer->flags, | ||
| 1000 | (timer->flags & ~TIMER_BASEMASK) | cpu); | ||
| 1001 | } | ||
| 1002 | |||
| 987 | debug_activate(timer, timer->expires); | 1003 | debug_activate(timer, timer->expires); |
| 988 | internal_add_timer(base, timer); | 1004 | internal_add_timer(base, timer); |
| 989 | spin_unlock_irqrestore(&base->lock, flags); | 1005 | spin_unlock_irqrestore(&base->lock, flags); |
