summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2019-03-21 11:39:20 -0400
committerThomas Gleixner <tglx@linutronix.de>2019-03-23 13:26:43 -0400
commit1b72d43237980eab9b6ae6bb8181e51c840377e6 (patch)
treec515d7d02bda7e60dba5babdd36d97b650c66ec6
parente1e41b6ce5f9c1a80bf4f2404ec5ab11c6c5a2ad (diff)
tick: Remove outgoing CPU from broadcast masks
Valentin reported that unplugging a CPU occasionally results in a warning in the tick broadcast code which is triggered when an offline CPU is in the broadcast mask. This happens because the outgoing CPU is not removing itself from the broadcast masks, especially not from the broadcast_force_mask. The removal happens on the control CPU after the outgoing CPU is dead. It's a long standing issue, but the warning is harmless. Rework the hotplug mechanism so that the outgoing CPU removes itself from the broadcast masks after disabling interrupts and removing itself from the online mask. Reported-by: Valentin Schneider <valentin.schneider@arm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Valentin Schneider <valentin.schneider@arm.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1903211540180.1784@nanos.tec.linutronix.de
-rw-r--r--include/linux/tick.h6
-rw-r--r--kernel/cpu.c2
-rw-r--r--kernel/time/clockevents.c18
-rw-r--r--kernel/time/tick-broadcast.c40
-rw-r--r--kernel/time/tick-internal.h10
5 files changed, 49 insertions, 27 deletions
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 55388ab45fd4..76acb48acdb7 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -68,6 +68,12 @@ extern void tick_broadcast_control(enum tick_broadcast_mode mode);
68static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { } 68static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { }
69#endif /* BROADCAST */ 69#endif /* BROADCAST */
70 70
71#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_HOTPLUG_CPU)
72extern void tick_offline_cpu(unsigned int cpu);
73#else
74static inline void tick_offline_cpu(unsigned int cpu) { }
75#endif
76
71#ifdef CONFIG_GENERIC_CLOCKEVENTS 77#ifdef CONFIG_GENERIC_CLOCKEVENTS
72extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state); 78extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state);
73#else 79#else
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 025f419d16f6..f69ba38573c2 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -844,6 +844,8 @@ static int take_cpu_down(void *_param)
844 844
845 /* Give up timekeeping duties */ 845 /* Give up timekeeping duties */
846 tick_handover_do_timer(); 846 tick_handover_do_timer();
847 /* Remove CPU from timer broadcasting */
848 tick_offline_cpu(cpu);
847 /* Park the stopper thread */ 849 /* Park the stopper thread */
848 stop_machine_park(cpu); 850 stop_machine_park(cpu);
849 return 0; 851 return 0;
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 5e77662dd2d9..f5490222e134 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -611,6 +611,22 @@ void clockevents_resume(void)
611} 611}
612 612
613#ifdef CONFIG_HOTPLUG_CPU 613#ifdef CONFIG_HOTPLUG_CPU
614
615# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
616/**
617 * tick_offline_cpu - Take CPU out of the broadcast mechanism
618 * @cpu: The outgoing CPU
619 *
620 * Called on the outgoing CPU after it took itself offline.
621 */
622void tick_offline_cpu(unsigned int cpu)
623{
624 raw_spin_lock(&clockevents_lock);
625 tick_broadcast_offline(cpu);
626 raw_spin_unlock(&clockevents_lock);
627}
628# endif
629
614/** 630/**
615 * tick_cleanup_dead_cpu - Cleanup the tick and clockevents of a dead cpu 631 * tick_cleanup_dead_cpu - Cleanup the tick and clockevents of a dead cpu
616 */ 632 */
@@ -621,8 +637,6 @@ void tick_cleanup_dead_cpu(int cpu)
621 637
622 raw_spin_lock_irqsave(&clockevents_lock, flags); 638 raw_spin_lock_irqsave(&clockevents_lock, flags);
623 639
624 tick_shutdown_broadcast_oneshot(cpu);
625 tick_shutdown_broadcast(cpu);
626 tick_shutdown(cpu); 640 tick_shutdown(cpu);
627 /* 641 /*
628 * Unregister the clock event devices which were 642 * Unregister the clock event devices which were
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index ee834d4fb814..0283523de045 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -36,10 +36,12 @@ static __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
36static void tick_broadcast_setup_oneshot(struct clock_event_device *bc); 36static void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
37static void tick_broadcast_clear_oneshot(int cpu); 37static void tick_broadcast_clear_oneshot(int cpu);
38static void tick_resume_broadcast_oneshot(struct clock_event_device *bc); 38static void tick_resume_broadcast_oneshot(struct clock_event_device *bc);
39static void tick_broadcast_oneshot_offline(unsigned int cpu);
39#else 40#else
40static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { BUG(); } 41static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { BUG(); }
41static inline void tick_broadcast_clear_oneshot(int cpu) { } 42static inline void tick_broadcast_clear_oneshot(int cpu) { }
42static inline void tick_resume_broadcast_oneshot(struct clock_event_device *bc) { } 43static inline void tick_resume_broadcast_oneshot(struct clock_event_device *bc) { }
44static inline void tick_broadcast_oneshot_offline(unsigned int cpu) { }
43#endif 45#endif
44 46
45/* 47/*
@@ -433,27 +435,29 @@ void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
433} 435}
434 436
435#ifdef CONFIG_HOTPLUG_CPU 437#ifdef CONFIG_HOTPLUG_CPU
436/* 438static void tick_shutdown_broadcast(void)
437 * Remove a CPU from broadcasting
438 */
439void tick_shutdown_broadcast(unsigned int cpu)
440{ 439{
441 struct clock_event_device *bc; 440 struct clock_event_device *bc = tick_broadcast_device.evtdev;
442 unsigned long flags;
443
444 raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
445
446 bc = tick_broadcast_device.evtdev;
447 cpumask_clear_cpu(cpu, tick_broadcast_mask);
448 cpumask_clear_cpu(cpu, tick_broadcast_on);
449 441
450 if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) { 442 if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
451 if (bc && cpumask_empty(tick_broadcast_mask)) 443 if (bc && cpumask_empty(tick_broadcast_mask))
452 clockevents_shutdown(bc); 444 clockevents_shutdown(bc);
453 } 445 }
446}
454 447
455 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); 448/*
449 * Remove a CPU from broadcasting
450 */
451void tick_broadcast_offline(unsigned int cpu)
452{
453 raw_spin_lock(&tick_broadcast_lock);
454 cpumask_clear_cpu(cpu, tick_broadcast_mask);
455 cpumask_clear_cpu(cpu, tick_broadcast_on);
456 tick_broadcast_oneshot_offline(cpu);
457 tick_shutdown_broadcast();
458 raw_spin_unlock(&tick_broadcast_lock);
456} 459}
460
457#endif 461#endif
458 462
459void tick_suspend_broadcast(void) 463void tick_suspend_broadcast(void)
@@ -950,14 +954,10 @@ void hotplug_cpu__broadcast_tick_pull(int deadcpu)
950} 954}
951 955
952/* 956/*
953 * Remove a dead CPU from broadcasting 957 * Remove a dying CPU from broadcasting
954 */ 958 */
955void tick_shutdown_broadcast_oneshot(unsigned int cpu) 959static void tick_broadcast_oneshot_offline(unsigned int cpu)
956{ 960{
957 unsigned long flags;
958
959 raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
960
961 /* 961 /*
962 * Clear the broadcast masks for the dead cpu, but do not stop 962 * Clear the broadcast masks for the dead cpu, but do not stop
963 * the broadcast device! 963 * the broadcast device!
@@ -965,8 +965,6 @@ void tick_shutdown_broadcast_oneshot(unsigned int cpu)
965 cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask); 965 cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
966 cpumask_clear_cpu(cpu, tick_broadcast_pending_mask); 966 cpumask_clear_cpu(cpu, tick_broadcast_pending_mask);
967 cpumask_clear_cpu(cpu, tick_broadcast_force_mask); 967 cpumask_clear_cpu(cpu, tick_broadcast_force_mask);
968
969 raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
970} 968}
971#endif 969#endif
972 970
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index e277284c2831..7b2496136729 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -64,7 +64,6 @@ extern ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt);
64extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu); 64extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu);
65extern void tick_install_broadcast_device(struct clock_event_device *dev); 65extern void tick_install_broadcast_device(struct clock_event_device *dev);
66extern int tick_is_broadcast_device(struct clock_event_device *dev); 66extern int tick_is_broadcast_device(struct clock_event_device *dev);
67extern void tick_shutdown_broadcast(unsigned int cpu);
68extern void tick_suspend_broadcast(void); 67extern void tick_suspend_broadcast(void);
69extern void tick_resume_broadcast(void); 68extern void tick_resume_broadcast(void);
70extern bool tick_resume_check_broadcast(void); 69extern bool tick_resume_check_broadcast(void);
@@ -78,7 +77,6 @@ static inline void tick_install_broadcast_device(struct clock_event_device *dev)
78static inline int tick_is_broadcast_device(struct clock_event_device *dev) { return 0; } 77static inline int tick_is_broadcast_device(struct clock_event_device *dev) { return 0; }
79static inline int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) { return 0; } 78static inline int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) { return 0; }
80static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { } 79static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { }
81static inline void tick_shutdown_broadcast(unsigned int cpu) { }
82static inline void tick_suspend_broadcast(void) { } 80static inline void tick_suspend_broadcast(void) { }
83static inline void tick_resume_broadcast(void) { } 81static inline void tick_resume_broadcast(void) { }
84static inline bool tick_resume_check_broadcast(void) { return false; } 82static inline bool tick_resume_check_broadcast(void) { return false; }
@@ -128,19 +126,23 @@ static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
128/* Functions related to oneshot broadcasting */ 126/* Functions related to oneshot broadcasting */
129#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT) 127#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
130extern void tick_broadcast_switch_to_oneshot(void); 128extern void tick_broadcast_switch_to_oneshot(void);
131extern void tick_shutdown_broadcast_oneshot(unsigned int cpu);
132extern int tick_broadcast_oneshot_active(void); 129extern int tick_broadcast_oneshot_active(void);
133extern void tick_check_oneshot_broadcast_this_cpu(void); 130extern void tick_check_oneshot_broadcast_this_cpu(void);
134bool tick_broadcast_oneshot_available(void); 131bool tick_broadcast_oneshot_available(void);
135extern struct cpumask *tick_get_broadcast_oneshot_mask(void); 132extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
136#else /* !(BROADCAST && ONESHOT): */ 133#else /* !(BROADCAST && ONESHOT): */
137static inline void tick_broadcast_switch_to_oneshot(void) { } 134static inline void tick_broadcast_switch_to_oneshot(void) { }
138static inline void tick_shutdown_broadcast_oneshot(unsigned int cpu) { }
139static inline int tick_broadcast_oneshot_active(void) { return 0; } 135static inline int tick_broadcast_oneshot_active(void) { return 0; }
140static inline void tick_check_oneshot_broadcast_this_cpu(void) { } 136static inline void tick_check_oneshot_broadcast_this_cpu(void) { }
141static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); } 137static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); }
142#endif /* !(BROADCAST && ONESHOT) */ 138#endif /* !(BROADCAST && ONESHOT) */
143 139
140#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_HOTPLUG_CPU)
141extern void tick_broadcast_offline(unsigned int cpu);
142#else
143static inline void tick_broadcast_offline(unsigned int cpu) { }
144#endif
145
144/* NO_HZ_FULL internal */ 146/* NO_HZ_FULL internal */
145#ifdef CONFIG_NO_HZ_FULL 147#ifdef CONFIG_NO_HZ_FULL
146extern void tick_nohz_init(void); 148extern void tick_nohz_init(void);