mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
Merge "hrtimer: make sure PINNED flag is cleared after removing hrtimer"
This commit is contained in:
commit
a7abbe4fa3
2 changed files with 65 additions and 16 deletions
|
|
@ -73,6 +73,7 @@ enum hrtimer_restart {
|
|||
*
|
||||
* 0x00 inactive
|
||||
* 0x01 enqueued into rbtree
|
||||
* 0x02 timer is pinned to a cpu
|
||||
*
|
||||
* The callback state is not part of the timer->state because clearing it would
|
||||
* mean touching the timer after the callback, this makes it impossible to free
|
||||
|
|
@ -92,6 +93,8 @@ enum hrtimer_restart {
|
|||
*/
|
||||
#define HRTIMER_STATE_INACTIVE 0x00
|
||||
#define HRTIMER_STATE_ENQUEUED 0x01
|
||||
#define HRTIMER_PINNED_SHIFT 1
|
||||
#define HRTIMER_STATE_PINNED (1 << HRTIMER_PINNED_SHIFT)
|
||||
|
||||
/**
|
||||
* struct hrtimer - the basic hrtimer structure
|
||||
|
|
@ -371,6 +374,9 @@ static inline void hrtimer_cancel_wait_running(struct hrtimer *timer)
|
|||
|
||||
/* Exported timer functions: */
|
||||
|
||||
/* To be used from cpusets, only */
|
||||
extern void hrtimer_quiesce_cpu(void *cpup);
|
||||
|
||||
/* Initialize timers: */
|
||||
extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock,
|
||||
enum hrtimer_mode mode);
|
||||
|
|
|
|||
|
|
@ -966,7 +966,7 @@ static int enqueue_hrtimer(struct hrtimer *timer,
|
|||
|
||||
base->cpu_base->active_bases |= 1 << base->index;
|
||||
|
||||
timer->state = HRTIMER_STATE_ENQUEUED;
|
||||
timer->state |= HRTIMER_STATE_ENQUEUED;
|
||||
|
||||
return timerqueue_add(&base->active, &timer->node);
|
||||
}
|
||||
|
|
@ -986,11 +986,9 @@ static void __remove_hrtimer(struct hrtimer *timer,
|
|||
u8 newstate, int reprogram)
|
||||
{
|
||||
struct hrtimer_cpu_base *cpu_base = base->cpu_base;
|
||||
u8 state = timer->state;
|
||||
|
||||
timer->state = newstate;
|
||||
if (!(state & HRTIMER_STATE_ENQUEUED))
|
||||
return;
|
||||
if (!(timer->state & HRTIMER_STATE_ENQUEUED))
|
||||
goto out;
|
||||
|
||||
if (!timerqueue_del(&base->active, &timer->node))
|
||||
cpu_base->active_bases &= ~(1 << base->index);
|
||||
|
|
@ -1005,6 +1003,13 @@ static void __remove_hrtimer(struct hrtimer *timer,
|
|||
*/
|
||||
if (reprogram && timer == cpu_base->next_timer)
|
||||
hrtimer_force_reprogram(cpu_base, 1);
|
||||
|
||||
out:
|
||||
/*
|
||||
* We need to preserve PINNED state here, otherwise we may end up
|
||||
* migrating pinned hrtimers as well.
|
||||
*/
|
||||
timer->state = newstate | (timer->state & HRTIMER_STATE_PINNED);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1032,6 +1037,7 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool rest
|
|||
state = HRTIMER_STATE_INACTIVE;
|
||||
|
||||
__remove_hrtimer(timer, base, state, reprogram);
|
||||
timer->state &= ~HRTIMER_STATE_PINNED;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1097,6 +1103,10 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
|
|||
/* Switch the timer base, if necessary: */
|
||||
new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
|
||||
|
||||
/* Update pinned state */
|
||||
timer->state &= ~HRTIMER_STATE_PINNED;
|
||||
timer->state |= (!!(mode & HRTIMER_MODE_PINNED)) << HRTIMER_PINNED_SHIFT;
|
||||
|
||||
return enqueue_hrtimer(timer, new_base, mode);
|
||||
}
|
||||
|
||||
|
|
@ -2004,13 +2014,17 @@ int hrtimers_prepare_cpu(unsigned int cpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
|
||||
#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_CPUSETS)
|
||||
static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
|
||||
struct hrtimer_clock_base *new_base)
|
||||
struct hrtimer_clock_base *new_base,
|
||||
bool remove_pinned)
|
||||
{
|
||||
struct hrtimer *timer;
|
||||
struct timerqueue_node *node;
|
||||
struct timerqueue_head pinned;
|
||||
int is_pinned;
|
||||
|
||||
timerqueue_init_head(&pinned);
|
||||
|
||||
while ((node = timerqueue_getnext(&old_base->active))) {
|
||||
timer = container_of(node, struct hrtimer, node);
|
||||
|
|
@ -2023,6 +2037,13 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
|
|||
* under us on another CPU
|
||||
*/
|
||||
__remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0);
|
||||
|
||||
is_pinned = timer->state & HRTIMER_STATE_PINNED;
|
||||
if (!remove_pinned && is_pinned) {
|
||||
timerqueue_add(&pinned, &timer->node);
|
||||
continue;
|
||||
}
|
||||
|
||||
timer->base = new_base;
|
||||
/*
|
||||
* Enqueue the timers on the new cpu. This does not
|
||||
|
|
@ -2034,23 +2055,29 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
|
|||
*/
|
||||
enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS);
|
||||
}
|
||||
|
||||
/* Re-queue pinned timers for non-hotplug usecase */
|
||||
while ((node = timerqueue_getnext(&pinned))) {
|
||||
timer = container_of(node, struct hrtimer, node);
|
||||
|
||||
timerqueue_del(&pinned, &timer->node);
|
||||
enqueue_hrtimer(timer, old_base, HRTIMER_MODE_ABS);
|
||||
}
|
||||
}
|
||||
|
||||
int hrtimers_dead_cpu(unsigned int scpu)
|
||||
static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned)
|
||||
{
|
||||
struct hrtimer_cpu_base *old_base, *new_base;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
BUG_ON(cpu_online(scpu));
|
||||
tick_cancel_sched_timer(scpu);
|
||||
|
||||
/*
|
||||
* this BH disable ensures that raise_softirq_irqoff() does
|
||||
* not wakeup ksoftirqd (and acquire the pi-lock) while
|
||||
* holding the cpu_base lock
|
||||
*/
|
||||
local_bh_disable();
|
||||
local_irq_disable();
|
||||
local_irq_save(flags);
|
||||
old_base = &per_cpu(hrtimer_bases, scpu);
|
||||
new_base = this_cpu_ptr(&hrtimer_bases);
|
||||
/*
|
||||
|
|
@ -2062,7 +2089,7 @@ int hrtimers_dead_cpu(unsigned int scpu)
|
|||
|
||||
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
|
||||
migrate_hrtimer_list(&old_base->clock_base[i],
|
||||
&new_base->clock_base[i]);
|
||||
&new_base->clock_base[i], remove_pinned);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2076,13 +2103,29 @@ int hrtimers_dead_cpu(unsigned int scpu)
|
|||
|
||||
/* Check, if we got expired work to do */
|
||||
__hrtimer_peek_ahead_timers();
|
||||
local_irq_enable();
|
||||
local_irq_restore(flags);
|
||||
local_bh_enable();
|
||||
}
|
||||
#endif /* CONFIG_HOTPLUG_CPU || CONFIG_CPUSETS */
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
int hrtimers_dead_cpu(unsigned int scpu)
|
||||
{
|
||||
BUG_ON(cpu_online(scpu));
|
||||
tick_cancel_sched_timer(scpu);
|
||||
|
||||
__migrate_hrtimers(scpu, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
#ifdef CONFIG_CPUSETS
|
||||
void hrtimer_quiesce_cpu(void *cpup)
|
||||
{
|
||||
__migrate_hrtimers(*(int *)cpup, false);
|
||||
}
|
||||
#endif /* CONFIG_CPUSETS */
|
||||
|
||||
void __init hrtimers_init(void)
|
||||
{
|
||||
hrtimers_prepare_cpu(smp_processor_id());
|
||||
|
|
|
|||
Loading…
Reference in a new issue