diff options
author | Viresh Kumar <viresh.kumar@linaro.org> | 2015-03-31 11:19:01 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-04-02 11:46:01 -0400 |
commit | 8def906044c02edcedac79aa3d6310ab4d90c4d8 (patch) | |
tree | ed23b9385e720c9da9958d8b56f06b0e3d548f76 | |
parent | b337a9380f7effd60d082569dd7e0b97a7549730 (diff) |
timer: Don't initialize 'tvec_base' on hotplug
There is no need to call init_timers_cpu() on every CPU hotplug event,
there is not much we need to reset.
- Timer-lists are already empty at the end of migrate_timers().
- timer_jiffies will be refreshed while adding a new timer, after the
CPU is online again.
- active_timers and all_timers can be reset from migrate_timers().
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/54a1c30ea7b805af55beb220cadf5a07a21b0a4d.1427814611.git.viresh.kumar@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | kernel/time/timer.c | 98 |
1 files changed, 43 insertions, 55 deletions
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index f3cc653f876c..1feb9c7035c0 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c | |||
@@ -1543,43 +1543,6 @@ signed long __sched schedule_timeout_uninterruptible(signed long timeout) | |||
1543 | } | 1543 | } |
1544 | EXPORT_SYMBOL(schedule_timeout_uninterruptible); | 1544 | EXPORT_SYMBOL(schedule_timeout_uninterruptible); |
1545 | 1545 | ||
1546 | static int init_timers_cpu(int cpu) | ||
1547 | { | ||
1548 | struct tvec_base *base = per_cpu(tvec_bases, cpu); | ||
1549 | static char tvec_base_done[NR_CPUS]; | ||
1550 | int j; | ||
1551 | |||
1552 | if (!tvec_base_done[cpu]) { | ||
1553 | static char boot_cpu_skipped; | ||
1554 | |||
1555 | if (!boot_cpu_skipped) { | ||
1556 | boot_cpu_skipped = 1; /* skip the boot cpu */ | ||
1557 | } else { | ||
1558 | base = per_cpu_ptr(&__tvec_bases, cpu); | ||
1559 | per_cpu(tvec_bases, cpu) = base; | ||
1560 | } | ||
1561 | |||
1562 | spin_lock_init(&base->lock); | ||
1563 | tvec_base_done[cpu] = 1; | ||
1564 | base->cpu = cpu; | ||
1565 | } | ||
1566 | |||
1567 | for (j = 0; j < TVN_SIZE; j++) { | ||
1568 | INIT_LIST_HEAD(base->tv5.vec + j); | ||
1569 | INIT_LIST_HEAD(base->tv4.vec + j); | ||
1570 | INIT_LIST_HEAD(base->tv3.vec + j); | ||
1571 | INIT_LIST_HEAD(base->tv2.vec + j); | ||
1572 | } | ||
1573 | for (j = 0; j < TVR_SIZE; j++) | ||
1574 | INIT_LIST_HEAD(base->tv1.vec + j); | ||
1575 | |||
1576 | base->timer_jiffies = jiffies; | ||
1577 | base->next_timer = base->timer_jiffies; | ||
1578 | base->active_timers = 0; | ||
1579 | base->all_timers = 0; | ||
1580 | return 0; | ||
1581 | } | ||
1582 | |||
1583 | #ifdef CONFIG_HOTPLUG_CPU | 1546 | #ifdef CONFIG_HOTPLUG_CPU |
1584 | static void migrate_timer_list(struct tvec_base *new_base, struct list_head *head) | 1547 | static void migrate_timer_list(struct tvec_base *new_base, struct list_head *head) |
1585 | { | 1548 | { |
@@ -1621,6 +1584,9 @@ static void migrate_timers(int cpu) | |||
1621 | migrate_timer_list(new_base, old_base->tv5.vec + i); | 1584 | migrate_timer_list(new_base, old_base->tv5.vec + i); |
1622 | } | 1585 | } |
1623 | 1586 | ||
1587 | old_base->active_timers = 0; | ||
1588 | old_base->all_timers = 0; | ||
1589 | |||
1624 | spin_unlock(&old_base->lock); | 1590 | spin_unlock(&old_base->lock); |
1625 | spin_unlock_irq(&new_base->lock); | 1591 | spin_unlock_irq(&new_base->lock); |
1626 | put_cpu_var(tvec_bases); | 1592 | put_cpu_var(tvec_bases); |
@@ -1630,25 +1596,16 @@ static void migrate_timers(int cpu) | |||
1630 | static int timer_cpu_notify(struct notifier_block *self, | 1596 | static int timer_cpu_notify(struct notifier_block *self, |
1631 | unsigned long action, void *hcpu) | 1597 | unsigned long action, void *hcpu) |
1632 | { | 1598 | { |
1633 | long cpu = (long)hcpu; | ||
1634 | int err; | ||
1635 | |||
1636 | switch(action) { | ||
1637 | case CPU_UP_PREPARE: | ||
1638 | case CPU_UP_PREPARE_FROZEN: | ||
1639 | err = init_timers_cpu(cpu); | ||
1640 | if (err < 0) | ||
1641 | return notifier_from_errno(err); | ||
1642 | break; | ||
1643 | #ifdef CONFIG_HOTPLUG_CPU | 1599 | #ifdef CONFIG_HOTPLUG_CPU |
1600 | switch (action) { | ||
1644 | case CPU_DEAD: | 1601 | case CPU_DEAD: |
1645 | case CPU_DEAD_FROZEN: | 1602 | case CPU_DEAD_FROZEN: |
1646 | migrate_timers(cpu); | 1603 | migrate_timers((long)hcpu); |
1647 | break; | 1604 | break; |
1648 | #endif | ||
1649 | default: | 1605 | default: |
1650 | break; | 1606 | break; |
1651 | } | 1607 | } |
1608 | #endif | ||
1652 | return NOTIFY_OK; | 1609 | return NOTIFY_OK; |
1653 | } | 1610 | } |
1654 | 1611 | ||
@@ -1656,18 +1613,49 @@ static struct notifier_block timers_nb = { | |||
1656 | .notifier_call = timer_cpu_notify, | 1613 | .notifier_call = timer_cpu_notify, |
1657 | }; | 1614 | }; |
1658 | 1615 | ||
1616 | static void __init init_timer_cpu(struct tvec_base *base, int cpu) | ||
1617 | { | ||
1618 | int j; | ||
1659 | 1619 | ||
1660 | void __init init_timers(void) | 1620 | base->cpu = cpu; |
1621 | per_cpu(tvec_bases, cpu) = base; | ||
1622 | spin_lock_init(&base->lock); | ||
1623 | |||
1624 | for (j = 0; j < TVN_SIZE; j++) { | ||
1625 | INIT_LIST_HEAD(base->tv5.vec + j); | ||
1626 | INIT_LIST_HEAD(base->tv4.vec + j); | ||
1627 | INIT_LIST_HEAD(base->tv3.vec + j); | ||
1628 | INIT_LIST_HEAD(base->tv2.vec + j); | ||
1629 | } | ||
1630 | for (j = 0; j < TVR_SIZE; j++) | ||
1631 | INIT_LIST_HEAD(base->tv1.vec + j); | ||
1632 | |||
1633 | base->timer_jiffies = jiffies; | ||
1634 | base->next_timer = base->timer_jiffies; | ||
1635 | } | ||
1636 | |||
1637 | static void __init init_timer_cpus(void) | ||
1661 | { | 1638 | { |
1662 | int err; | 1639 | struct tvec_base *base; |
1640 | int local_cpu = smp_processor_id(); | ||
1641 | int cpu; | ||
1642 | |||
1643 | for_each_possible_cpu(cpu) { | ||
1644 | if (cpu == local_cpu) | ||
1645 | base = &boot_tvec_bases; | ||
1646 | else | ||
1647 | base = per_cpu_ptr(&__tvec_bases, cpu); | ||
1648 | |||
1649 | init_timer_cpu(base, cpu); | ||
1650 | } | ||
1651 | } | ||
1663 | 1652 | ||
1653 | void __init init_timers(void) | ||
1654 | { | ||
1664 | /* ensure there are enough low bits for flags in timer->base pointer */ | 1655 | /* ensure there are enough low bits for flags in timer->base pointer */ |
1665 | BUILD_BUG_ON(__alignof__(struct tvec_base) & TIMER_FLAG_MASK); | 1656 | BUILD_BUG_ON(__alignof__(struct tvec_base) & TIMER_FLAG_MASK); |
1666 | 1657 | ||
1667 | err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE, | 1658 | init_timer_cpus(); |
1668 | (void *)(long)smp_processor_id()); | ||
1669 | BUG_ON(err != NOTIFY_OK); | ||
1670 | |||
1671 | init_timer_stats(); | 1659 | init_timer_stats(); |
1672 | register_cpu_notifier(&timers_nb); | 1660 | register_cpu_notifier(&timers_nb); |
1673 | open_softirq(TIMER_SOFTIRQ, run_timer_softirq); | 1661 | open_softirq(TIMER_SOFTIRQ, run_timer_softirq); |