Skip to content

Commit 8553f32

Browse files
committed
Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: timers: fix build error in !oneshot case x86: c1e_idle: don't mark TSC unstable if CPU has invariant TSC x86: prevent C-states hang on AMD C1E enabled machines clockevents: prevent mode mismatch on cpu online clockevents: check broadcast device not tick device clockevents: prevent stale tick_next_period for onlining CPUs x86: prevent stale state of c1e_mask across CPU offline/online clockevents: prevent cpu online to interfere with nohz
2 parents be3be89 + f8e256c commit 8553f32

File tree

10 files changed

+50
-15
lines changed

10 files changed

+50
-15
lines changed

arch/x86/kernel/process.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,21 @@ static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c)
246246
return 1;
247247
}
248248

249+
static cpumask_t c1e_mask = CPU_MASK_NONE;
250+
static int c1e_detected;
251+
252+
void c1e_remove_cpu(int cpu)
253+
{
254+
cpu_clear(cpu, c1e_mask);
255+
}
256+
249257
/*
250258
* C1E aware idle routine. We check for C1E active in the interrupt
251259
* pending message MSR. If we detect C1E, then we handle it the same
252260
* way as C3 power states (local apic timer and TSC stop)
253261
*/
254262
static void c1e_idle(void)
255263
{
256-
static cpumask_t c1e_mask = CPU_MASK_NONE;
257-
static int c1e_detected;
258-
259264
if (need_resched())
260265
return;
261266

@@ -265,8 +270,10 @@ static void c1e_idle(void)
265270
rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
266271
if (lo & K8_INTP_C1E_ACTIVE_MASK) {
267272
c1e_detected = 1;
268-
mark_tsc_unstable("TSC halt in C1E");
269-
printk(KERN_INFO "System has C1E enabled\n");
273+
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
274+
mark_tsc_unstable("TSC halt in AMD C1E");
275+
printk(KERN_INFO "System has AMD C1E enabled\n");
276+
set_cpu_cap(&boot_cpu_data, X86_FEATURE_AMDC1E);
270277
}
271278
}
272279

arch/x86/kernel/process_32.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ static void cpu_exit_clear(void)
8888
cpu_clear(cpu, cpu_callin_map);
8989

9090
numa_remove_cpu(cpu);
91+
c1e_remove_cpu(cpu);
9192
}
9293

9394
/* We don't actually take CPU down, just spin without interrupts. */

arch/x86/kernel/process_64.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ DECLARE_PER_CPU(int, cpu_state);
9393
static inline void play_dead(void)
9494
{
9595
idle_task_exit();
96+
c1e_remove_cpu(raw_smp_processor_id());
97+
9698
mb();
9799
/* Ack it */
98100
__get_cpu_var(cpu_state) = CPU_DEAD;

include/asm-x86/acpi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate)
140140
boot_cpu_data.x86_model <= 0x05 &&
141141
boot_cpu_data.x86_mask < 0x0A)
142142
return 1;
143+
else if (boot_cpu_has(X86_FEATURE_AMDC1E))
144+
return 1;
143145
else
144146
return max_cstate;
145147
}

include/asm-x86/cpufeature.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
8282
#define X86_FEATURE_11AP (3*32+19) /* Bad local APIC aka 11AP */
8383
#define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */
84+
#define X86_FEATURE_AMDC1E (3*32+21) /* AMD C1E detected */
8485

8586
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
8687
#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */

include/asm-x86/idle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ void idle_notifier_register(struct notifier_block *n);
1010
void enter_idle(void);
1111
void exit_idle(void);
1212

13+
void c1e_remove_cpu(int cpu);
14+
1315
#endif

kernel/time/tick-broadcast.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ static void tick_do_broadcast_on_off(void *why)
235235
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
236236
if (!cpu_isset(cpu, tick_broadcast_mask)) {
237237
cpu_set(cpu, tick_broadcast_mask);
238-
if (td->mode == TICKDEV_MODE_PERIODIC)
238+
if (bc->mode == TICKDEV_MODE_PERIODIC)
239239
clockevents_shutdown(dev);
240240
}
241241
if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
@@ -245,7 +245,7 @@ static void tick_do_broadcast_on_off(void *why)
245245
if (!tick_broadcast_force &&
246246
cpu_isset(cpu, tick_broadcast_mask)) {
247247
cpu_clear(cpu, tick_broadcast_mask);
248-
if (td->mode == TICKDEV_MODE_PERIODIC)
248+
if (bc->mode == TICKDEV_MODE_PERIODIC)
249249
tick_setup_periodic(dev, 0);
250250
}
251251
break;
@@ -575,4 +575,12 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
575575
spin_unlock_irqrestore(&tick_broadcast_lock, flags);
576576
}
577577

578+
/*
579+
* Check, whether the broadcast device is in one shot mode
580+
*/
581+
int tick_broadcast_oneshot_active(void)
582+
{
583+
return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT;
584+
}
585+
578586
#endif

kernel/time/tick-common.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
3333
*/
3434
ktime_t tick_next_period;
3535
ktime_t tick_period;
36-
int tick_do_timer_cpu __read_mostly = -1;
36+
int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT;
3737
DEFINE_SPINLOCK(tick_device_lock);
3838

3939
/*
@@ -109,7 +109,8 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
109109
if (!tick_device_is_functional(dev))
110110
return;
111111

112-
if (dev->features & CLOCK_EVT_FEAT_PERIODIC) {
112+
if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
113+
!tick_broadcast_oneshot_active()) {
113114
clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
114115
} else {
115116
unsigned long seq;
@@ -148,7 +149,7 @@ static void tick_setup_device(struct tick_device *td,
148149
* If no cpu took the do_timer update, assign it to
149150
* this cpu:
150151
*/
151-
if (tick_do_timer_cpu == -1) {
152+
if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) {
152153
tick_do_timer_cpu = cpu;
153154
tick_next_period = ktime_get();
154155
tick_period = ktime_set(0, NSEC_PER_SEC / HZ);
@@ -300,7 +301,8 @@ static void tick_shutdown(unsigned int *cpup)
300301
if (*cpup == tick_do_timer_cpu) {
301302
int cpu = first_cpu(cpu_online_map);
302303

303-
tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : -1;
304+
tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu :
305+
TICK_DO_TIMER_NONE;
304306
}
305307
spin_unlock_irqrestore(&tick_device_lock, flags);
306308
}

kernel/time/tick-internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
/*
22
* tick internal variable and functions used by low/high res code
33
*/
4+
5+
#define TICK_DO_TIMER_NONE -1
6+
#define TICK_DO_TIMER_BOOT -2
7+
48
DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
59
extern spinlock_t tick_device_lock;
610
extern ktime_t tick_next_period;
@@ -31,6 +35,7 @@ extern void tick_broadcast_oneshot_control(unsigned long reason);
3135
extern void tick_broadcast_switch_to_oneshot(void);
3236
extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
3337
extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
38+
extern int tick_broadcast_oneshot_active(void);
3439
# else /* BROADCAST */
3540
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
3641
{
@@ -39,6 +44,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
3944
static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
4045
static inline void tick_broadcast_switch_to_oneshot(void) { }
4146
static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
47+
static inline int tick_broadcast_oneshot_active(void) { return 0; }
4248
# endif /* !BROADCAST */
4349

4450
#else /* !ONESHOT */
@@ -68,6 +74,7 @@ static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
6874
{
6975
return 0;
7076
}
77+
static inline int tick_broadcast_oneshot_active(void) { return 0; }
7178
#endif /* !TICK_ONESHOT */
7279

7380
/*

kernel/time/tick-sched.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ static void tick_do_update_jiffies64(ktime_t now)
7575
incr * ticks);
7676
}
7777
do_timer(++ticks);
78+
79+
/* Keep the tick_next_period variable up to date */
80+
tick_next_period = ktime_add(last_jiffies_update, tick_period);
7881
}
7982
write_sequnlock(&xtime_lock);
8083
}
@@ -221,7 +224,7 @@ void tick_nohz_stop_sched_tick(int inidle)
221224
*/
222225
if (unlikely(!cpu_online(cpu))) {
223226
if (cpu == tick_do_timer_cpu)
224-
tick_do_timer_cpu = -1;
227+
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
225228
}
226229

227230
if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
@@ -303,7 +306,7 @@ void tick_nohz_stop_sched_tick(int inidle)
303306
* invoked.
304307
*/
305308
if (cpu == tick_do_timer_cpu)
306-
tick_do_timer_cpu = -1;
309+
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
307310

308311
ts->idle_sleeps++;
309312

@@ -468,7 +471,7 @@ static void tick_nohz_handler(struct clock_event_device *dev)
468471
* this duty, then the jiffies update is still serialized by
469472
* xtime_lock.
470473
*/
471-
if (unlikely(tick_do_timer_cpu == -1))
474+
if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
472475
tick_do_timer_cpu = cpu;
473476

474477
/* Check, if the jiffies need an update */
@@ -570,7 +573,7 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
570573
* this duty, then the jiffies update is still serialized by
571574
* xtime_lock.
572575
*/
573-
if (unlikely(tick_do_timer_cpu == -1))
576+
if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
574577
tick_do_timer_cpu = cpu;
575578
#endif
576579

0 commit comments

Comments
 (0)