Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/blackfin/kernel/irqchip.c
10817 views
1
/*
2
* Copyright 2005-2009 Analog Devices Inc.
3
*
4
* Licensed under the GPL-2 or later
5
*/
6
7
#include <linux/kernel_stat.h>
8
#include <linux/module.h>
9
#include <linux/random.h>
10
#include <linux/seq_file.h>
11
#include <linux/kallsyms.h>
12
#include <linux/interrupt.h>
13
#include <linux/irq.h>
14
#include <asm/irq_handler.h>
15
#include <asm/trace.h>
16
#include <asm/pda.h>
17
18
static atomic_t irq_err_count;
19
void ack_bad_irq(unsigned int irq)
20
{
21
atomic_inc(&irq_err_count);
22
printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
23
}
24
25
static struct irq_desc bad_irq_desc = {
26
.handle_irq = handle_bad_irq,
27
.lock = __RAW_SPIN_LOCK_UNLOCKED(bad_irq_desc.lock),
28
};
29
30
#ifdef CONFIG_CPUMASK_OFFSTACK
31
/* We are not allocating a variable-sized bad_irq_desc.affinity */
32
#error "Blackfin architecture does not support CONFIG_CPUMASK_OFFSTACK."
33
#endif
34
35
#ifdef CONFIG_PROC_FS
36
int show_interrupts(struct seq_file *p, void *v)
37
{
38
int i = *(loff_t *) v, j;
39
struct irqaction *action;
40
unsigned long flags;
41
42
if (i < NR_IRQS) {
43
struct irq_desc *desc = irq_to_desc(i);
44
45
raw_spin_lock_irqsave(&desc->lock, flags);
46
action = desc->action;
47
if (!action)
48
goto skip;
49
seq_printf(p, "%3d: ", i);
50
for_each_online_cpu(j)
51
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
52
seq_printf(p, " %8s", irq_desc_get_chip(desc)->name);
53
seq_printf(p, " %s", action->name);
54
for (action = action->next; action; action = action->next)
55
seq_printf(p, " %s", action->name);
56
57
seq_putc(p, '\n');
58
skip:
59
raw_spin_unlock_irqrestore(&desc->lock, flags);
60
} else if (i == NR_IRQS) {
61
seq_printf(p, "NMI: ");
62
for_each_online_cpu(j)
63
seq_printf(p, "%10u ", cpu_pda[j].__nmi_count);
64
seq_printf(p, " CORE Non Maskable Interrupt\n");
65
seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
66
}
67
return 0;
68
}
69
#endif
70
71
#ifdef CONFIG_DEBUG_STACKOVERFLOW
72
static void check_stack_overflow(int irq)
73
{
74
/* Debugging check for stack overflow: is there less than STACK_WARN free? */
75
long sp = __get_SP() & (THREAD_SIZE - 1);
76
77
if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
78
dump_stack();
79
pr_emerg("irq%i: possible stack overflow only %ld bytes free\n",
80
irq, sp - sizeof(struct thread_info));
81
}
82
}
83
#else
84
static inline void check_stack_overflow(int irq) { }
85
#endif
86
87
#ifndef CONFIG_IPIPE
88
static void maybe_lower_to_irq14(void)
89
{
90
unsigned short pending, other_ints;
91
92
/*
93
* If we're the only interrupt running (ignoring IRQ15 which
94
* is for syscalls), lower our priority to IRQ14 so that
95
* softirqs run at that level. If there's another,
96
* lower-level interrupt, irq_exit will defer softirqs to
97
* that. If the interrupt pipeline is enabled, we are already
98
* running at IRQ14 priority, so we don't need this code.
99
*/
100
CSYNC();
101
pending = bfin_read_IPEND() & ~0x8000;
102
other_ints = pending & (pending - 1);
103
if (other_ints == 0)
104
lower_to_irq14();
105
}
106
#else
107
static inline void maybe_lower_to_irq14(void) { }
108
#endif
109
110
/*
111
* do_IRQ handles all hardware IRQs. Decoded IRQs should not
112
* come via this function. Instead, they should provide their
113
* own 'handler'
114
*/
115
#ifdef CONFIG_DO_IRQ_L1
116
__attribute__((l1_text))
117
#endif
118
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
119
{
120
struct pt_regs *old_regs = set_irq_regs(regs);
121
122
irq_enter();
123
124
check_stack_overflow(irq);
125
126
/*
127
* Some hardware gives randomly wrong interrupts. Rather
128
* than crashing, do something sensible.
129
*/
130
if (irq >= NR_IRQS)
131
handle_bad_irq(irq, &bad_irq_desc);
132
else
133
generic_handle_irq(irq);
134
135
maybe_lower_to_irq14();
136
137
irq_exit();
138
139
set_irq_regs(old_regs);
140
}
141
142
void __init init_IRQ(void)
143
{
144
init_arch_irq();
145
146
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
147
/* Now that evt_ivhw is set up, turn this on */
148
trace_buff_offset = 0;
149
bfin_write_TBUFCTL(BFIN_TRACE_ON);
150
printk(KERN_INFO "Hardware Trace expanded to %ik\n",
151
1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);
152
#endif
153
}
154
155