Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branches 'irq-urgent-for-linus' and 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq and timer fixes from Thomas Gleixner:

- An irq regression fix to restore the wakeup behaviour of chained
interrupts.

- A timer fix for a long standing race versus timers scheduled on a
target cpu which got exposed by recent changes in the workqueue
implementation.

* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
genirq/PM: Restore system wake up from chained interrupts

* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
timers: Use proper base migration in add_timer_on()

+27 -5
+5
kernel/irq/internals.h
··· 199 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 207 #ifdef CONFIG_PM_SLEEP 203 208 bool irq_pm_check_wakeup(struct irq_desc *desc); 204 209 void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action);
+2 -1
kernel/irq/pm.c
··· 70 70 71 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 75 return false; 75 76 76 77 if (irqd_is_wakeup_set(&desc->irq_data)) {
+1 -1
kernel/irq/proc.c
··· 475 475 for_each_online_cpu(j) 476 476 any_count |= kstat_irqs_cpu(i, j); 477 477 action = desc->action; 478 - if ((!action || action == &chained_action) && !any_count) 478 + if ((!action || irq_desc_is_chained(desc)) && !any_count) 479 479 goto out; 480 480 481 481 seq_printf(p, "%*d: ", prec, i);
+19 -3
kernel/time/timer.c
··· 977 977 */ 978 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 982 unsigned long flags; 982 983 983 984 timer_stats_timer_set_start_info(timer); 984 985 BUG_ON(timer_pending(timer) || !timer->function); 985 - spin_lock_irqsave(&base->lock, flags); 986 - timer->flags = (timer->flags & ~TIMER_BASEMASK) | cpu; 986 + 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 1003 debug_activate(timer, timer->expires); 988 1004 internal_add_timer(base, timer); 989 1005 spin_unlock_irqrestore(&base->lock, flags);