• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
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  
9  #include <linux/module.h>
10  #include <linux/types.h>
11  #include <linux/sched.h>
12  #include <linux/interrupt.h>
13  #include <linux/errno.h>
14  #include <linux/init.h>
15  #include <linux/irq.h>
16  
17  #include <asm/setup.h>
18  #include <asm/irq.h>
19  #include <asm/traps.h>
20  #include <asm/page.h>
21  #include <asm/machdep.h>
22  #include <asm/cacheflush.h>
23  #include <asm/irq_regs.h>
24  
25  #ifdef CONFIG_Q40
26  #include <asm/q40ints.h>
27  #endif
28  
29  extern u32 auto_irqhandler_fixup[];
30  extern u16 user_irqvec_fixup[];
31  
32  static int m68k_first_user_vec;
33  
34  static struct irq_chip auto_irq_chip = {
35  	.name		= "auto",
36  	.irq_startup	= m68k_irq_startup,
37  	.irq_shutdown	= m68k_irq_shutdown,
38  };
39  
40  static struct irq_chip user_irq_chip = {
41  	.name		= "user",
42  	.irq_startup	= m68k_irq_startup,
43  	.irq_shutdown	= m68k_irq_shutdown,
44  };
45  
46  /*
47   * void init_IRQ(void)
48   *
49   * Parameters:	None
50   *
51   * Returns:	Nothing
52   *
53   * This function should be called during kernel startup to initialize
54   * the IRQ handling routines.
55   */
56  
init_IRQ(void)57  void __init init_IRQ(void)
58  {
59  	int i;
60  
61  	for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++)
62  		irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq);
63  
64  	mach_init_IRQ();
65  }
66  
67  /**
68   * m68k_setup_auto_interrupt
69   * @handler: called from auto vector interrupts
70   *
71   * setup the handler to be called from auto vector interrupts instead of the
72   * standard do_IRQ(), it will be called with irq numbers in the range
73   * from IRQ_AUTO_1 - IRQ_AUTO_7.
74   */
m68k_setup_auto_interrupt(void (* handler)(unsigned int,struct pt_regs *))75  void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
76  {
77  	if (handler)
78  		*auto_irqhandler_fixup = (u32)handler;
79  	flush_icache();
80  }
81  
82  /**
83   * m68k_setup_user_interrupt
84   * @vec: first user vector interrupt to handle
85   * @cnt: number of active user vector interrupts
86   *
87   * setup user vector interrupts, this includes activating the specified range
88   * of interrupts, only then these interrupts can be requested (note: this is
89   * different from auto vector interrupts).
90   */
m68k_setup_user_interrupt(unsigned int vec,unsigned int cnt)91  void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt)
92  {
93  	int i;
94  
95  	BUG_ON(IRQ_USER + cnt > NR_IRQS);
96  	m68k_first_user_vec = vec;
97  	for (i = 0; i < cnt; i++)
98  		irq_set_chip_and_handler(i, &user_irq_chip, handle_simple_irq);
99  	*user_irqvec_fixup = vec - IRQ_USER;
100  	flush_icache();
101  }
102  
103  /**
104   * m68k_setup_irq_controller
105   * @chip: irq chip which controls specified irq
106   * @handle: flow handler which handles specified irq
107   * @irq: first irq to be managed by the controller
108   * @cnt: number of irqs to be managed by the controller
109   *
110   * Change the controller for the specified range of irq, which will be used to
111   * manage these irq. auto/user irq already have a default controller, which can
112   * be changed as well, but the controller probably should use m68k_irq_startup/
113   * m68k_irq_shutdown.
114   */
m68k_setup_irq_controller(struct irq_chip * chip,irq_flow_handler_t handle,unsigned int irq,unsigned int cnt)115  void m68k_setup_irq_controller(struct irq_chip *chip,
116  			       irq_flow_handler_t handle, unsigned int irq,
117  			       unsigned int cnt)
118  {
119  	int i;
120  
121  	for (i = 0; i < cnt; i++) {
122  		irq_set_chip(irq + i, chip);
123  		if (handle)
124  			irq_set_handler(irq + i, handle);
125  	}
126  }
127  
m68k_irq_startup_irq(unsigned int irq)128  unsigned int m68k_irq_startup_irq(unsigned int irq)
129  {
130  	if (irq <= IRQ_AUTO_7)
131  		vectors[VEC_SPUR + irq] = auto_inthandler;
132  	else
133  		vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler;
134  	return 0;
135  }
136  
m68k_irq_startup(struct irq_data * data)137  unsigned int m68k_irq_startup(struct irq_data *data)
138  {
139  	return m68k_irq_startup_irq(data->irq);
140  }
141  
m68k_irq_shutdown(struct irq_data * data)142  void m68k_irq_shutdown(struct irq_data *data)
143  {
144  	unsigned int irq = data->irq;
145  
146  	if (irq <= IRQ_AUTO_7)
147  		vectors[VEC_SPUR + irq] = bad_inthandler;
148  	else
149  		vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
150  }
151  
152  
irq_canonicalize(unsigned int irq)153  unsigned int irq_canonicalize(unsigned int irq)
154  {
155  #ifdef CONFIG_Q40
156  	if (MACH_IS_Q40 && irq == 11)
157  		irq = 10;
158  #endif
159  	return irq;
160  }
161  
162  EXPORT_SYMBOL(irq_canonicalize);
163  
164  
handle_badint(struct pt_regs * regs)165  asmlinkage void handle_badint(struct pt_regs *regs)
166  {
167  	atomic_inc(&irq_err_count);
168  	pr_warn("unexpected interrupt from %u\n", regs->vector);
169  }
170