import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm64 / kernel / irq.c
CommitLineData
fb9bd7d6
MZ
1/*
2 * Based on arch/arm/kernel/irq.c
3 *
4 * Copyright (C) 1992 Linus Torvalds
5 * Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
6 * Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation.
7 * Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and
8 * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>.
9 * Copyright (C) 2012 ARM Ltd.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include <linux/kernel_stat.h>
25#include <linux/irq.h>
26#include <linux/smp.h>
27#include <linux/init.h>
e851b58c 28#include <linux/irqchip.h>
fb9bd7d6
MZ
29#include <linux/seq_file.h>
30#include <linux/ratelimit.h>
31
6fa3eb70 32#include <linux/mt_sched_mon.h>
fb9bd7d6
MZ
33unsigned long irq_err_count;
34
35int arch_show_interrupts(struct seq_file *p, int prec)
36{
37#ifdef CONFIG_SMP
38 show_ipi_list(p, prec);
39#endif
40 seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
41 return 0;
42}
43
6fa3eb70
S
44#ifdef CONFIG_MTK_SCHED_TRACERS
45#include <trace/events/mtk_events.h>
46#endif
47
fb9bd7d6
MZ
48/*
49 * handle_IRQ handles all hardware IRQ's. Decoded IRQs should
50 * not come via this function. Instead, they should provide their
51 * own 'handler'. Used by platform code implementing C-based 1st
52 * level decoding.
53 */
54void handle_IRQ(unsigned int irq, struct pt_regs *regs)
55{
56 struct pt_regs *old_regs = set_irq_regs(regs);
6fa3eb70
S
57#ifdef CONFIG_MTK_SCHED_TRACERS
58 struct irq_desc *desc;
59#endif
fb9bd7d6
MZ
60
61 irq_enter();
6fa3eb70
S
62 mt_trace_ISR_start(irq);
63#ifdef CONFIG_MTK_SCHED_TRACERS
64 desc = irq_to_desc(irq);
65 trace_irq_entry(irq,
66 (desc && desc->action && desc->action->name) ? desc->action->name : "-");
67#endif
fb9bd7d6
MZ
68
69 /*
70 * Some hardware gives randomly wrong interrupts. Rather
71 * than crashing, do something sensible.
72 */
73 if (unlikely(irq >= nr_irqs)) {
74 pr_warn_ratelimited("Bad IRQ%u\n", irq);
75 ack_bad_irq(irq);
76 } else {
77 generic_handle_irq(irq);
78 }
6fa3eb70
S
79#ifdef CONFIG_MTK_SCHED_TRACERS
80 trace_irq_exit(irq);
81#endif
82 mt_trace_ISR_end(irq);
fb9bd7d6
MZ
83 irq_exit();
84 set_irq_regs(old_regs);
85}
86
e851b58c
CM
87void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
88{
89 if (handle_arch_irq)
90 return;
91
92 handle_arch_irq = handle_irq;
93}
fb9bd7d6
MZ
94
95void __init init_IRQ(void)
96{
e851b58c 97 irqchip_init();
fb9bd7d6
MZ
98 if (!handle_arch_irq)
99 panic("No interrupt controller found.");
100}
6fa3eb70
S
101
102#ifdef CONFIG_HOTPLUG_CPU
103static bool migrate_one_irq(struct irq_desc *desc)
104{
105 struct irq_data *d = irq_desc_get_irq_data(desc);
106 const struct cpumask *affinity = d->affinity;
107 struct irq_chip *c;
108 bool ret = false;
109
110 /*
111 * If this is a per-CPU interrupt, or the affinity does not
112 * include this CPU, then we have nothing to do.
113 */
114 if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity))
115 return false;
116
117 if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
118 affinity = cpu_online_mask;
119 ret = true;
120 }
121
122 c = irq_data_get_irq_chip(d);
123 if (!c->irq_set_affinity)
124 pr_debug("IRQ%u: unable to set affinity\n", d->irq);
125 else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret)
126 cpumask_copy(d->affinity, affinity);
127
128 return ret;
129}
130
131/*
132 * The current CPU has been marked offline. Migrate IRQs off this CPU.
133 * If the affinity settings do not allow other CPUs, force them onto any
134 * available CPU.
135 *
136 * Note: we must iterate over all IRQs, whether they have an attached
137 * action structure or not, as we need to get chained interrupts too.
138 */
139void migrate_irqs(void)
140{
141 unsigned int i;
142 struct irq_desc *desc;
143 unsigned long flags;
144
145 local_irq_save(flags);
146
147 for_each_irq_desc(i, desc) {
148 bool affinity_broken;
149
150 raw_spin_lock(&desc->lock);
151 affinity_broken = migrate_one_irq(desc);
152 raw_spin_unlock(&desc->lock);
153
154 if (affinity_broken)
155 pr_warn_ratelimited("IRQ%u no longer affine to CPU%u\n",
156 i, smp_processor_id());
157 }
158
159 local_irq_restore(flags);
160}
161#endif /* CONFIG_HOTPLUG_CPU */