Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/kernel/irq.c
10817 views
1
/*
2
* linux/arch/arm/kernel/irq.c
3
*
4
* Copyright (C) 1992 Linus Torvalds
5
* Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
6
*
7
* Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation.
8
* Dynamic Tick Timer written by Tony Lindgren <[email protected]> and
9
* Tuukka Tikkanen <[email protected]>.
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 file contains the code used by various IRQ handling routines:
16
* asking for different IRQ's should be done through these routines
17
* instead of just grabbing them. Thus setups with different IRQ numbers
18
* shouldn't result in any weird surprises, and installing new handlers
19
* should be easier.
20
*
21
* IRQ's are in fact implemented a bit like signal handlers for the kernel.
22
* Naturally it's not a 1:1 relation, but there are similarities.
23
*/
24
#include <linux/kernel_stat.h>
25
#include <linux/module.h>
26
#include <linux/signal.h>
27
#include <linux/ioport.h>
28
#include <linux/interrupt.h>
29
#include <linux/irq.h>
30
#include <linux/random.h>
31
#include <linux/smp.h>
32
#include <linux/init.h>
33
#include <linux/seq_file.h>
34
#include <linux/errno.h>
35
#include <linux/list.h>
36
#include <linux/kallsyms.h>
37
#include <linux/proc_fs.h>
38
#include <linux/ftrace.h>
39
40
#include <asm/system.h>
41
#include <asm/mach/arch.h>
42
#include <asm/mach/irq.h>
43
#include <asm/mach/time.h>
44
45
/*
46
* No architecture-specific irq_finish function defined in arm/arch/irqs.h.
47
*/
48
#ifndef irq_finish
49
#define irq_finish(irq) do { } while (0)
50
#endif
51
52
unsigned long irq_err_count;
53
54
int arch_show_interrupts(struct seq_file *p, int prec)
55
{
56
#ifdef CONFIG_FIQ
57
show_fiq_list(p, prec);
58
#endif
59
#ifdef CONFIG_SMP
60
show_ipi_list(p, prec);
61
#endif
62
#ifdef CONFIG_LOCAL_TIMERS
63
show_local_irqs(p, prec);
64
#endif
65
seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
66
return 0;
67
}
68
69
/*
70
* do_IRQ handles all hardware IRQ's. Decoded IRQs should not
71
* come via this function. Instead, they should provide their
72
* own 'handler'
73
*/
74
asmlinkage void __exception_irq_entry
75
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
76
{
77
struct pt_regs *old_regs = set_irq_regs(regs);
78
79
irq_enter();
80
81
/*
82
* Some hardware gives randomly wrong interrupts. Rather
83
* than crashing, do something sensible.
84
*/
85
if (unlikely(irq >= nr_irqs)) {
86
if (printk_ratelimit())
87
printk(KERN_WARNING "Bad IRQ%u\n", irq);
88
ack_bad_irq(irq);
89
} else {
90
generic_handle_irq(irq);
91
}
92
93
/* AT91 specific workaround */
94
irq_finish(irq);
95
96
irq_exit();
97
set_irq_regs(old_regs);
98
}
99
100
void set_irq_flags(unsigned int irq, unsigned int iflags)
101
{
102
unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
103
104
if (irq >= nr_irqs) {
105
printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
106
return;
107
}
108
109
if (iflags & IRQF_VALID)
110
clr |= IRQ_NOREQUEST;
111
if (iflags & IRQF_PROBE)
112
clr |= IRQ_NOPROBE;
113
if (!(iflags & IRQF_NOAUTOEN))
114
clr |= IRQ_NOAUTOEN;
115
/* Order is clear bits in "clr" then set bits in "set" */
116
irq_modify_status(irq, clr, set & ~clr);
117
}
118
119
void __init init_IRQ(void)
120
{
121
machine_desc->init_irq();
122
}
123
124
#ifdef CONFIG_SPARSE_IRQ
125
int __init arch_probe_nr_irqs(void)
126
{
127
nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS;
128
return nr_irqs;
129
}
130
#endif
131
132
#ifdef CONFIG_HOTPLUG_CPU
133
134
static bool migrate_one_irq(struct irq_data *d)
135
{
136
unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask);
137
bool ret = false;
138
139
if (cpu >= nr_cpu_ids) {
140
cpu = cpumask_any(cpu_online_mask);
141
ret = true;
142
}
143
144
pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu);
145
146
d->chip->irq_set_affinity(d, cpumask_of(cpu), true);
147
148
return ret;
149
}
150
151
/*
152
* The CPU has been marked offline. Migrate IRQs off this CPU. If
153
* the affinity settings do not allow other CPUs, force them onto any
154
* available CPU.
155
*/
156
void migrate_irqs(void)
157
{
158
unsigned int i, cpu = smp_processor_id();
159
struct irq_desc *desc;
160
unsigned long flags;
161
162
local_irq_save(flags);
163
164
for_each_irq_desc(i, desc) {
165
struct irq_data *d = &desc->irq_data;
166
bool affinity_broken = false;
167
168
raw_spin_lock(&desc->lock);
169
do {
170
if (desc->action == NULL)
171
break;
172
173
if (d->node != cpu)
174
break;
175
176
affinity_broken = migrate_one_irq(d);
177
} while (0);
178
raw_spin_unlock(&desc->lock);
179
180
if (affinity_broken && printk_ratelimit())
181
pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu);
182
}
183
184
local_irq_restore(flags);
185
}
186
#endif /* CONFIG_HOTPLUG_CPU */
187
188