• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/arch/m68knommu/platform/68328/
1/*
2 * linux/arch/m68knommu/platform/68328/ints.c
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License.  See the file COPYING in the main directory of this archive
6 * for more details.
7 *
8 * Copyright 1996 Roman Zippel
9 * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
10 */
11
12#include <linux/module.h>
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <linux/kernel_stat.h>
17#include <linux/errno.h>
18#include <linux/interrupt.h>
19
20#include <asm/system.h>
21#include <asm/irq.h>
22#include <asm/irqnode.h>
23#include <asm/traps.h>
24#include <asm/io.h>
25#include <asm/machdep.h>
26#include <asm/setup.h>
27
28#if defined(CONFIG_M68328)
29#include <asm/MC68328.h>
30#elif defined(CONFIG_M68EZ328)
31#include <asm/MC68EZ328.h>
32#elif defined(CONFIG_M68VZ328)
33#include <asm/MC68VZ328.h>
34#endif
35
36/* assembler routines */
37asmlinkage void system_call(void);
38asmlinkage void buserr(void);
39asmlinkage void trap(void);
40asmlinkage void trap3(void);
41asmlinkage void trap4(void);
42asmlinkage void trap5(void);
43asmlinkage void trap6(void);
44asmlinkage void trap7(void);
45asmlinkage void trap8(void);
46asmlinkage void trap9(void);
47asmlinkage void trap10(void);
48asmlinkage void trap11(void);
49asmlinkage void trap12(void);
50asmlinkage void trap13(void);
51asmlinkage void trap14(void);
52asmlinkage void trap15(void);
53asmlinkage void trap33(void);
54asmlinkage void trap34(void);
55asmlinkage void trap35(void);
56asmlinkage void trap36(void);
57asmlinkage void trap37(void);
58asmlinkage void trap38(void);
59asmlinkage void trap39(void);
60asmlinkage void trap40(void);
61asmlinkage void trap41(void);
62asmlinkage void trap42(void);
63asmlinkage void trap43(void);
64asmlinkage void trap44(void);
65asmlinkage void trap45(void);
66asmlinkage void trap46(void);
67asmlinkage void trap47(void);
68asmlinkage irqreturn_t bad_interrupt(int, void *);
69asmlinkage irqreturn_t inthandler(void);
70asmlinkage irqreturn_t inthandler1(void);
71asmlinkage irqreturn_t inthandler2(void);
72asmlinkage irqreturn_t inthandler3(void);
73asmlinkage irqreturn_t inthandler4(void);
74asmlinkage irqreturn_t inthandler5(void);
75asmlinkage irqreturn_t inthandler6(void);
76asmlinkage irqreturn_t inthandler7(void);
77
78extern e_vector *_ramvec;
79
80/* The number of spurious interrupts */
81volatile unsigned int num_spurious;
82unsigned int local_irq_count[NR_CPUS];
83
84/* irq node variables for the 32 (potential) on chip sources */
85static irq_node_t int_irq_list[NR_IRQS];
86
87/*
88 * This function should be called during kernel startup to initialize
89 * the IRQ handling routines.
90 */
91void init_IRQ(void)
92{
93	int i;
94
95	/* set up the vectors */
96	for (i = 72; i < 256; ++i)
97		_ramvec[i] = (e_vector) bad_interrupt;
98
99	_ramvec[32] = system_call;
100
101	_ramvec[65] = (e_vector) inthandler1;
102	_ramvec[66] = (e_vector) inthandler2;
103	_ramvec[67] = (e_vector) inthandler3;
104	_ramvec[68] = (e_vector) inthandler4;
105	_ramvec[69] = (e_vector) inthandler5;
106	_ramvec[70] = (e_vector) inthandler6;
107	_ramvec[71] = (e_vector) inthandler7;
108
109	IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
110
111	/* initialize handlers */
112	for (i = 0; i < NR_IRQS; i++) {
113		int_irq_list[i].handler = bad_interrupt;
114		int_irq_list[i].flags   = IRQ_FLG_STD;
115		int_irq_list[i].dev_id  = NULL;
116		int_irq_list[i].devname = NULL;
117	}
118
119	/* turn off all interrupts */
120	IMR = ~0;
121}
122
123int request_irq(
124	unsigned int irq,
125	irq_handler_t handler,
126	unsigned long flags,
127	const char *devname,
128	void *dev_id)
129{
130	if (irq >= NR_IRQS) {
131		printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
132		return -ENXIO;
133	}
134
135	if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) {
136		if (int_irq_list[irq].flags & IRQ_FLG_LOCK) {
137			printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n",
138			       __FUNCTION__, irq, int_irq_list[irq].devname);
139			return -EBUSY;
140		}
141		if (flags & IRQ_FLG_REPLACE) {
142			printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n",
143			       __FUNCTION__, devname, irq, int_irq_list[irq].devname);
144			return -EBUSY;
145		}
146	}
147
148	int_irq_list[irq].handler = handler;
149	int_irq_list[irq].flags   = flags;
150	int_irq_list[irq].dev_id  = dev_id;
151	int_irq_list[irq].devname = devname;
152
153	IMR &= ~(1<<irq);
154
155	return 0;
156}
157
158EXPORT_SYMBOL(request_irq);
159
160void free_irq(unsigned int irq, void *dev_id)
161{
162	if (irq >= NR_IRQS) {
163		printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
164		return;
165	}
166
167	if (int_irq_list[irq].dev_id != dev_id)
168		printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n",
169		       __FUNCTION__, irq, int_irq_list[irq].devname);
170
171	int_irq_list[irq].handler = bad_interrupt;
172	int_irq_list[irq].flags   = IRQ_FLG_STD;
173	int_irq_list[irq].dev_id  = NULL;
174	int_irq_list[irq].devname = NULL;
175
176	IMR |= 1<<irq;
177}
178
179EXPORT_SYMBOL(free_irq);
180
181int show_interrupts(struct seq_file *p, void *v)
182{
183	int i = *(loff_t *) v;
184
185	if (i < NR_IRQS) {
186		if (int_irq_list[i].devname) {
187			seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]);
188			if (int_irq_list[i].flags & IRQ_FLG_LOCK)
189				seq_printf(p, "L ");
190			else
191				seq_printf(p, "  ");
192			seq_printf(p, "%s\n", int_irq_list[i].devname);
193		}
194	}
195	if (i == NR_IRQS)
196		seq_printf(p, "   : %10u   spurious\n", num_spurious);
197
198	return 0;
199}
200
201/* The 68k family did not have a good way to determine the source
202 * of interrupts until later in the family.  The EC000 core does
203 * not provide the vector number on the stack, we vector everything
204 * into one vector and look in the blasted mask register...
205 * This code is designed to be fast, almost constant time, not clean!
206 */
207void process_int(int vec, struct pt_regs *fp)
208{
209	int irq;
210	int mask;
211
212	unsigned long pend = ISR;
213
214	while (pend) {
215		if (pend & 0x0000ffff) {
216			if (pend & 0x000000ff) {
217				if (pend & 0x0000000f) {
218					mask = 0x00000001;
219					irq = 0;
220				} else {
221					mask = 0x00000010;
222					irq = 4;
223				}
224			} else {
225				if (pend & 0x00000f00) {
226					mask = 0x00000100;
227					irq = 8;
228				} else {
229					mask = 0x00001000;
230					irq = 12;
231				}
232			}
233		} else {
234			if (pend & 0x00ff0000) {
235				if (pend & 0x000f0000) {
236					mask = 0x00010000;
237					irq = 16;
238				} else {
239					mask = 0x00100000;
240					irq = 20;
241				}
242			} else {
243				if (pend & 0x0f000000) {
244					mask = 0x01000000;
245					irq = 24;
246				} else {
247					mask = 0x10000000;
248					irq = 28;
249				}
250			}
251		}
252
253		while (! (mask & pend)) {
254			mask <<=1;
255			irq++;
256		}
257
258		kstat_cpu(0).irqs[irq]++;
259
260		if (int_irq_list[irq].handler) {
261			int_irq_list[irq].handler(irq, int_irq_list[irq].dev_id, fp);
262		} else {
263			printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the IMR...\n", irq);
264			IMR |= mask;
265		}
266		pend &= ~mask;
267	}
268}
269