Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
irq.c
Go to the documentation of this file.
1 /*
2  * Atheros AR71xx/AR724x/AR913x specific interrupt handling
3  *
4  * Copyright (C) 2010-2011 Jaiganesh Narayanan <[email protected]>
5  * Copyright (C) 2008-2011 Gabor Juhos <[email protected]>
6  * Copyright (C) 2008 Imre Kaloz <[email protected]>
7  *
8  * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published
12  * by the Free Software Foundation.
13  */
14 
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/interrupt.h>
18 #include <linux/irq.h>
19 
20 #include <asm/irq_cpu.h>
21 #include <asm/mipsregs.h>
22 
23 #include <asm/mach-ath79/ath79.h>
25 #include "common.h"
26 
27 static void (*ath79_ip2_handler)(void);
28 static void (*ath79_ip3_handler)(void);
29 
30 static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
31 {
33  u32 pending;
34 
37 
38  if (pending & MISC_INT_UART)
40 
41  else if (pending & MISC_INT_DMA)
43 
44  else if (pending & MISC_INT_PERFC)
46 
47  else if (pending & MISC_INT_TIMER)
49 
50  else if (pending & MISC_INT_TIMER2)
52 
53  else if (pending & MISC_INT_TIMER3)
55 
56  else if (pending & MISC_INT_TIMER4)
58 
59  else if (pending & MISC_INT_OHCI)
61 
62  else if (pending & MISC_INT_ERROR)
64 
65  else if (pending & MISC_INT_GPIO)
67 
68  else if (pending & MISC_INT_WDOG)
70 
71  else if (pending & MISC_INT_ETHSW)
73 
74  else
76 }
77 
78 static void ar71xx_misc_irq_unmask(struct irq_data *d)
79 {
80  unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
81  void __iomem *base = ath79_reset_base;
82  u32 t;
83 
85  __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
86 
87  /* flush write */
89 }
90 
91 static void ar71xx_misc_irq_mask(struct irq_data *d)
92 {
93  unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
94  void __iomem *base = ath79_reset_base;
95  u32 t;
96 
98  __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
99 
100  /* flush write */
102 }
103 
104 static void ar724x_misc_irq_ack(struct irq_data *d)
105 {
106  unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
107  void __iomem *base = ath79_reset_base;
108  u32 t;
109 
111  __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
112 
113  /* flush write */
115 }
116 
117 static struct irq_chip ath79_misc_irq_chip = {
118  .name = "MISC",
119  .irq_unmask = ar71xx_misc_irq_unmask,
120  .irq_mask = ar71xx_misc_irq_mask,
121 };
122 
123 static void __init ath79_misc_irq_init(void)
124 {
125  void __iomem *base = ath79_reset_base;
126  int i;
127 
130 
131  if (soc_is_ar71xx() || soc_is_ar913x())
132  ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
133  else if (soc_is_ar724x() || soc_is_ar933x() || soc_is_ar934x())
134  ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
135  else
136  BUG();
137 
138  for (i = ATH79_MISC_IRQ_BASE;
140  irq_set_chip_and_handler(i, &ath79_misc_irq_chip,
142  }
143 
144  irq_set_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler);
145 }
146 
147 static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc)
148 {
149  u32 status;
150 
151  disable_irq_nosync(irq);
152 
153  status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS);
154 
155  if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) {
158  } else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) {
161  } else {
163  }
164 
165  enable_irq(irq);
166 }
167 
168 static void ar934x_ip2_irq_init(void)
169 {
170  int i;
171 
172  for (i = ATH79_IP2_IRQ_BASE;
174  irq_set_chip_and_handler(i, &dummy_irq_chip,
176 
177  irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar934x_ip2_irq_dispatch);
178 }
179 
181 {
182  unsigned long pending;
183 
184  pending = read_c0_status() & read_c0_cause() & ST0_IM;
185 
186  if (pending & STATUSF_IP7)
188 
189  else if (pending & STATUSF_IP2)
190  ath79_ip2_handler();
191 
192  else if (pending & STATUSF_IP4)
194 
195  else if (pending & STATUSF_IP5)
197 
198  else if (pending & STATUSF_IP3)
199  ath79_ip3_handler();
200 
201  else if (pending & STATUSF_IP6)
203 
204  else
206 }
207 
208 /*
209  * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for
210  * these devices typically allocate coherent DMA memory, however the
211  * DMA controller may still have some unsynchronized data in the FIFO.
212  * Issue a flush in the handlers to ensure that the driver sees
213  * the update.
214  */
215 static void ar71xx_ip2_handler(void)
216 {
219 }
220 
221 static void ar724x_ip2_handler(void)
222 {
225 }
226 
227 static void ar913x_ip2_handler(void)
228 {
231 }
232 
233 static void ar933x_ip2_handler(void)
234 {
237 }
238 
239 static void ar934x_ip2_handler(void)
240 {
242 }
243 
244 static void ar71xx_ip3_handler(void)
245 {
248 }
249 
250 static void ar724x_ip3_handler(void)
251 {
254 }
255 
256 static void ar913x_ip3_handler(void)
257 {
260 }
261 
262 static void ar933x_ip3_handler(void)
263 {
266 }
267 
268 static void ar934x_ip3_handler(void)
269 {
272 }
273 
275 {
276  if (soc_is_ar71xx()) {
277  ath79_ip2_handler = ar71xx_ip2_handler;
278  ath79_ip3_handler = ar71xx_ip3_handler;
279  } else if (soc_is_ar724x()) {
280  ath79_ip2_handler = ar724x_ip2_handler;
281  ath79_ip3_handler = ar724x_ip3_handler;
282  } else if (soc_is_ar913x()) {
283  ath79_ip2_handler = ar913x_ip2_handler;
284  ath79_ip3_handler = ar913x_ip3_handler;
285  } else if (soc_is_ar933x()) {
286  ath79_ip2_handler = ar933x_ip2_handler;
287  ath79_ip3_handler = ar933x_ip3_handler;
288  } else if (soc_is_ar934x()) {
289  ath79_ip2_handler = ar934x_ip2_handler;
290  ath79_ip3_handler = ar934x_ip3_handler;
291  } else {
292  BUG();
293  }
294 
297  ath79_misc_irq_init();
298 
299  if (soc_is_ar934x())
300  ar934x_ip2_irq_init();
301 }