Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
int.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (C) 2005 Embedded Alley Solutions, Inc
4  * Ported to 2.6.
5  *
6  * Per Hallsmark, [email protected]
7  * Copyright (C) 2000, 2001 MIPS Technologies, Inc.
8  * Copyright (C) 2001 Ralf Baechle
9  *
10  * Cleaned up and bug fixing: Pete Popov, [email protected]
11  *
12  * This program is free software; you can distribute it and/or modify it
13  * under the terms of the GNU General Public License (Version 2) as
14  * published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  * for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
24  *
25  */
26 #include <linux/compiler.h>
27 #include <linux/init.h>
28 #include <linux/irq.h>
29 #include <linux/sched.h>
30 #include <linux/interrupt.h>
31 #include <linux/kernel_stat.h>
32 #include <linux/random.h>
33 #include <linux/module.h>
34 
35 #include <asm/io.h>
36 #include <int.h>
37 #include <uart.h>
38 
39 /* default prio for interrupts */
40 /* first one is a no-no so therefore always prio 0 (disabled) */
41 static char gic_prio[PNX8550_INT_GIC_TOTINT] = {
42  0, 1, 1, 1, 1, 15, 1, 1, 1, 1, // 0 - 9
43  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10 - 19
44  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20 - 29
45  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30 - 39
46  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 - 49
47  1, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 50 - 59
48  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 - 69
49  1 // 70
50 };
51 
52 static void hw0_irqdispatch(int irq)
53 {
54  /* find out which interrupt */
55  irq = PNX8550_GIC_VECTOR_0 >> 3;
56 
57  if (irq == 0) {
58  printk("hw0_irqdispatch: irq 0, spurious interrupt?\n");
59  return;
60  }
62 }
63 
64 
65 static void timer_irqdispatch(int irq)
66 {
67  irq = (0x01c0 & read_c0_config7()) >> 6;
68 
69  if (unlikely(irq == 0)) {
70  printk("timer_irqdispatch: irq 0, spurious interrupt?\n");
71  return;
72  }
73 
74  if (irq & 0x1)
76  if (irq & 0x2)
78  if (irq & 0x4)
80 }
81 
83 {
84  unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
85 
86  if (pending & STATUSF_IP2)
87  hw0_irqdispatch(2);
88  else if (pending & STATUSF_IP7) {
89  if (read_c0_config7() & 0x01c0)
90  timer_irqdispatch(7);
91  } else
93 }
94 
95 static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
96 {
97  unsigned long status = read_c0_status();
98 
99  status &= ~((clr_mask & 0xFF) << 8);
100  status |= (set_mask & 0xFF) << 8;
101 
102  write_c0_status(status);
103 }
104 
105 static inline void mask_gic_int(unsigned int irq_nr)
106 {
107  /* interrupt disabled, bit 26(WE_ENABLE)=1 and bit 16(enable)=0 */
108  PNX8550_GIC_REQ(irq_nr) = 1<<28; /* set priority to 0 */
109 }
110 
111 static inline void unmask_gic_int(unsigned int irq_nr)
112 {
113  /* set prio mask to lower four bits and enable interrupt */
114  PNX8550_GIC_REQ(irq_nr) = (1<<26 | 1<<16) | (1<<28) | gic_prio[irq_nr];
115 }
116 
117 static inline void mask_irq(struct irq_data *d)
118 {
119  unsigned int irq_nr = d->irq;
120 
121  if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) {
122  modify_cp0_intmask(1 << irq_nr, 0);
123  } else if ((PNX8550_INT_GIC_MIN <= irq_nr) &&
124  (irq_nr <= PNX8550_INT_GIC_MAX)) {
125  mask_gic_int(irq_nr - PNX8550_INT_GIC_MIN);
126  } else if ((PNX8550_INT_TIMER_MIN <= irq_nr) &&
127  (irq_nr <= PNX8550_INT_TIMER_MAX)) {
128  modify_cp0_intmask(1 << 7, 0);
129  } else {
130  printk("mask_irq: irq %d doesn't exist!\n", irq_nr);
131  }
132 }
133 
134 static inline void unmask_irq(struct irq_data *d)
135 {
136  unsigned int irq_nr = d->irq;
137 
138  if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) {
139  modify_cp0_intmask(0, 1 << irq_nr);
140  } else if ((PNX8550_INT_GIC_MIN <= irq_nr) &&
141  (irq_nr <= PNX8550_INT_GIC_MAX)) {
142  unmask_gic_int(irq_nr - PNX8550_INT_GIC_MIN);
143  } else if ((PNX8550_INT_TIMER_MIN <= irq_nr) &&
144  (irq_nr <= PNX8550_INT_TIMER_MAX)) {
145  modify_cp0_intmask(0, 1 << 7);
146  } else {
147  printk("mask_irq: irq %d doesn't exist!\n", irq_nr);
148  }
149 }
150 
152 {
153  int gic_irq = irq-PNX8550_INT_GIC_MIN;
154  int prev_priority = PNX8550_GIC_REQ(gic_irq) & 0xf;
155 
156  gic_prio[gic_irq] = priority;
157  PNX8550_GIC_REQ(gic_irq) |= (0x10000000 | gic_prio[gic_irq]);
158 
159  return prev_priority;
160 }
161 
162 static struct irq_chip level_irq_type = {
163  .name = "PNX Level IRQ",
164  .irq_mask = mask_irq,
165  .irq_unmask = unmask_irq,
166 };
167 
168 static struct irqaction gic_action = {
169  .handler = no_action,
170  .flags = IRQF_NO_THREAD,
171  .name = "GIC",
172 };
173 
174 static struct irqaction timer_action = {
175  .handler = no_action,
176  .flags = IRQF_TIMER,
177  .name = "Timer",
178 };
179 
181 {
182  int i;
183  int configPR;
184 
185  for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++)
186  irq_set_chip_and_handler(i, &level_irq_type, handle_level_irq);
187 
188  /* init of GIC/IPC interrupts */
189  /* should be done before cp0 since cp0 init enables the GIC int */
190  for (i = PNX8550_INT_GIC_MIN; i <= PNX8550_INT_GIC_MAX; i++) {
191  int gic_int_line = i - PNX8550_INT_GIC_MIN;
192  if (gic_int_line == 0 )
193  continue; // don't fiddle with int 0
194  /*
195  * enable change of TARGET, ENABLE and ACTIVE_LOW bits
196  * set TARGET 0 to route through hw0 interrupt
197  * set ACTIVE_LOW 0 active high (correct?)
198  *
199  * We really should setup an interrupt description table
200  * to do this nicely.
201  * Note, PCI INTA is active low on the bus, but inverted
202  * in the GIC, so to us it's active high.
203  */
204  PNX8550_GIC_REQ(i - PNX8550_INT_GIC_MIN) = 0x1E000000;
205 
206  /* mask/priority is still 0 so we will not get any
207  * interrupts until it is unmasked */
208 
209  irq_set_chip_and_handler(i, &level_irq_type, handle_level_irq);
210  }
211 
212  /* Priority level 0 */
214 
215  /* Set int vector table address */
217 
218  irq_set_chip_and_handler(MIPS_CPU_GIC_IRQ, &level_irq_type,
220  setup_irq(MIPS_CPU_GIC_IRQ, &gic_action);
221 
222  /* init of Timer interrupts */
223  for (i = PNX8550_INT_TIMER_MIN; i <= PNX8550_INT_TIMER_MAX; i++)
224  irq_set_chip_and_handler(i, &level_irq_type, handle_level_irq);
225 
226  /* Stop Timer 1-3 */
227  configPR = read_c0_config7();
228  configPR |= 0x00000038;
229  write_c0_config7(configPR);
230 
231  irq_set_chip_and_handler(MIPS_CPU_TIMER_IRQ, &level_irq_type,
233  setup_irq(MIPS_CPU_TIMER_IRQ, &timer_action);
234 }
235