mlx4_en: Removing HW info from ethtool -i report.
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / mips / bcm63xx / irq.c
blob3be87f2422f0357ddd16411c4fa0d406dc21cbe1
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
7 * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr>
8 */
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/module.h>
14 #include <linux/irq.h>
15 #include <asm/irq_cpu.h>
16 #include <asm/mipsregs.h>
17 #include <bcm63xx_cpu.h>
18 #include <bcm63xx_regs.h>
19 #include <bcm63xx_io.h>
20 #include <bcm63xx_irq.h>
23 * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
24 * prioritize any interrupt relatively to another. the static counter
25 * will resume the loop where it ended the last time we left this
26 * function.
28 static void bcm63xx_irq_dispatch_internal(void)
30 u32 pending;
31 static int i;
33 pending = bcm_perf_readl(PERF_IRQMASK_REG) &
34 bcm_perf_readl(PERF_IRQSTAT_REG);
36 if (!pending)
37 return ;
39 while (1) {
40 int to_call = i;
42 i = (i + 1) & 0x1f;
43 if (pending & (1 << to_call)) {
44 do_IRQ(to_call + IRQ_INTERNAL_BASE);
45 break;
50 asmlinkage void plat_irq_dispatch(void)
52 u32 cause;
54 do {
55 cause = read_c0_cause() & read_c0_status() & ST0_IM;
57 if (!cause)
58 break;
60 if (cause & CAUSEF_IP7)
61 do_IRQ(7);
62 if (cause & CAUSEF_IP2)
63 bcm63xx_irq_dispatch_internal();
64 if (cause & CAUSEF_IP3)
65 do_IRQ(IRQ_EXT_0);
66 if (cause & CAUSEF_IP4)
67 do_IRQ(IRQ_EXT_1);
68 if (cause & CAUSEF_IP5)
69 do_IRQ(IRQ_EXT_2);
70 if (cause & CAUSEF_IP6)
71 do_IRQ(IRQ_EXT_3);
72 } while (1);
76 * internal IRQs operations: only mask/unmask on PERF irq mask
77 * register.
79 static inline void bcm63xx_internal_irq_mask(unsigned int irq)
81 u32 mask;
83 irq -= IRQ_INTERNAL_BASE;
84 mask = bcm_perf_readl(PERF_IRQMASK_REG);
85 mask &= ~(1 << irq);
86 bcm_perf_writel(mask, PERF_IRQMASK_REG);
89 static void bcm63xx_internal_irq_unmask(unsigned int irq)
91 u32 mask;
93 irq -= IRQ_INTERNAL_BASE;
94 mask = bcm_perf_readl(PERF_IRQMASK_REG);
95 mask |= (1 << irq);
96 bcm_perf_writel(mask, PERF_IRQMASK_REG);
99 static unsigned int bcm63xx_internal_irq_startup(unsigned int irq)
101 bcm63xx_internal_irq_unmask(irq);
102 return 0;
106 * external IRQs operations: mask/unmask and clear on PERF external
107 * irq control register.
109 static void bcm63xx_external_irq_mask(unsigned int irq)
111 u32 reg;
113 irq -= IRQ_EXT_BASE;
114 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
115 reg &= ~EXTIRQ_CFG_MASK(irq);
116 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
119 static void bcm63xx_external_irq_unmask(unsigned int irq)
121 u32 reg;
123 irq -= IRQ_EXT_BASE;
124 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
125 reg |= EXTIRQ_CFG_MASK(irq);
126 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
129 static void bcm63xx_external_irq_clear(unsigned int irq)
131 u32 reg;
133 irq -= IRQ_EXT_BASE;
134 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
135 reg |= EXTIRQ_CFG_CLEAR(irq);
136 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
139 static unsigned int bcm63xx_external_irq_startup(unsigned int irq)
141 set_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
142 irq_enable_hazard();
143 bcm63xx_external_irq_unmask(irq);
144 return 0;
147 static void bcm63xx_external_irq_shutdown(unsigned int irq)
149 bcm63xx_external_irq_mask(irq);
150 clear_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
151 irq_disable_hazard();
154 static int bcm63xx_external_irq_set_type(unsigned int irq,
155 unsigned int flow_type)
157 u32 reg;
158 struct irq_desc *desc = irq_desc + irq;
160 irq -= IRQ_EXT_BASE;
162 flow_type &= IRQ_TYPE_SENSE_MASK;
164 if (flow_type == IRQ_TYPE_NONE)
165 flow_type = IRQ_TYPE_LEVEL_LOW;
167 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
168 switch (flow_type) {
169 case IRQ_TYPE_EDGE_BOTH:
170 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
171 reg |= EXTIRQ_CFG_BOTHEDGE(irq);
172 break;
174 case IRQ_TYPE_EDGE_RISING:
175 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
176 reg |= EXTIRQ_CFG_SENSE(irq);
177 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
178 break;
180 case IRQ_TYPE_EDGE_FALLING:
181 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
182 reg &= ~EXTIRQ_CFG_SENSE(irq);
183 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
184 break;
186 case IRQ_TYPE_LEVEL_HIGH:
187 reg |= EXTIRQ_CFG_LEVELSENSE(irq);
188 reg |= EXTIRQ_CFG_SENSE(irq);
189 break;
191 case IRQ_TYPE_LEVEL_LOW:
192 reg |= EXTIRQ_CFG_LEVELSENSE(irq);
193 reg &= ~EXTIRQ_CFG_SENSE(irq);
194 break;
196 default:
197 printk(KERN_ERR "bogus flow type combination given !\n");
198 return -EINVAL;
200 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
202 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
203 desc->status |= IRQ_LEVEL;
204 desc->handle_irq = handle_level_irq;
205 } else {
206 desc->handle_irq = handle_edge_irq;
209 return 0;
212 static struct irq_chip bcm63xx_internal_irq_chip = {
213 .name = "bcm63xx_ipic",
214 .startup = bcm63xx_internal_irq_startup,
215 .shutdown = bcm63xx_internal_irq_mask,
217 .mask = bcm63xx_internal_irq_mask,
218 .mask_ack = bcm63xx_internal_irq_mask,
219 .unmask = bcm63xx_internal_irq_unmask,
222 static struct irq_chip bcm63xx_external_irq_chip = {
223 .name = "bcm63xx_epic",
224 .startup = bcm63xx_external_irq_startup,
225 .shutdown = bcm63xx_external_irq_shutdown,
227 .ack = bcm63xx_external_irq_clear,
229 .mask = bcm63xx_external_irq_mask,
230 .unmask = bcm63xx_external_irq_unmask,
232 .set_type = bcm63xx_external_irq_set_type,
235 static struct irqaction cpu_ip2_cascade_action = {
236 .handler = no_action,
237 .name = "cascade_ip2",
240 void __init arch_init_irq(void)
242 int i;
244 mips_cpu_irq_init();
245 for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
246 set_irq_chip_and_handler(i, &bcm63xx_internal_irq_chip,
247 handle_level_irq);
249 for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i)
250 set_irq_chip_and_handler(i, &bcm63xx_external_irq_chip,
251 handle_edge_irq);
253 setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action);