blob: 4d6bd8f6ee292ff17ab8fbdd4500e0929b1eceaf [file] [log] [blame]
Jayachandran C0c965402011-11-11 17:08:29 +05301/*
2 * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
3 * reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the NetLogic
9 * license below:
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <linux/kernel.h>
36#include <linux/init.h>
37#include <linux/linkage.h>
38#include <linux/interrupt.h>
39#include <linux/spinlock.h>
40#include <linux/mm.h>
41#include <linux/slab.h>
42#include <linux/irq.h>
43
44#include <asm/errno.h>
45#include <asm/signal.h>
Jayachandran C0c965402011-11-11 17:08:29 +053046#include <asm/ptrace.h>
47#include <asm/mipsregs.h>
48#include <asm/thread_info.h>
49
50#include <asm/netlogic/mips-extns.h>
51#include <asm/netlogic/interrupt.h>
52#include <asm/netlogic/haldefs.h>
53#include <asm/netlogic/common.h>
54
Jayachandran C65040e22011-11-16 00:21:28 +000055#if defined(CONFIG_CPU_XLP)
56#include <asm/netlogic/xlp-hal/iomap.h>
57#include <asm/netlogic/xlp-hal/xlp.h>
58#include <asm/netlogic/xlp-hal/pic.h>
59#elif defined(CONFIG_CPU_XLR)
Jayachandran C0c965402011-11-11 17:08:29 +053060#include <asm/netlogic/xlr/iomap.h>
61#include <asm/netlogic/xlr/pic.h>
Jayachandran C65040e22011-11-16 00:21:28 +000062#else
63#error "Unknown CPU"
64#endif
Jayachandran C0c965402011-11-11 17:08:29 +053065/*
66 * These are the routines that handle all the low level interrupt stuff.
67 * Actions handled here are: initialization of the interrupt map, requesting of
68 * interrupt lines by handlers, dispatching if interrupts to handlers, probing
69 * for interrupt lines
70 */
71
72/* Globals */
Jayachandran C0c965402011-11-11 17:08:29 +053073static void xlp_pic_enable(struct irq_data *d)
74{
75 unsigned long flags;
Jayachandran C77ae7982012-10-31 12:01:39 +000076 struct nlm_soc_info *nodep;
Jayachandran C0c965402011-11-11 17:08:29 +053077 int irt;
78
Jayachandran C77ae7982012-10-31 12:01:39 +000079 nodep = nlm_current_node();
Jayachandran C0c965402011-11-11 17:08:29 +053080 irt = nlm_irq_to_irt(d->irq);
81 if (irt == -1)
82 return;
Jayachandran C77ae7982012-10-31 12:01:39 +000083 spin_lock_irqsave(&nodep->piclock, flags);
84 nlm_pic_enable_irt(nodep->picbase, irt);
85 spin_unlock_irqrestore(&nodep->piclock, flags);
Jayachandran C0c965402011-11-11 17:08:29 +053086}
87
88static void xlp_pic_disable(struct irq_data *d)
89{
Jayachandran C77ae7982012-10-31 12:01:39 +000090 struct nlm_soc_info *nodep;
Jayachandran C0c965402011-11-11 17:08:29 +053091 unsigned long flags;
92 int irt;
93
Jayachandran C77ae7982012-10-31 12:01:39 +000094 nodep = nlm_current_node();
Jayachandran C0c965402011-11-11 17:08:29 +053095 irt = nlm_irq_to_irt(d->irq);
96 if (irt == -1)
97 return;
Jayachandran C77ae7982012-10-31 12:01:39 +000098 spin_lock_irqsave(&nodep->piclock, flags);
99 nlm_pic_disable_irt(nodep->picbase, irt);
100 spin_unlock_irqrestore(&nodep->piclock, flags);
Jayachandran C0c965402011-11-11 17:08:29 +0530101}
102
103static void xlp_pic_mask_ack(struct irq_data *d)
104{
105 uint64_t mask = 1ull << d->irq;
106
107 write_c0_eirr(mask); /* ack by writing EIRR */
108}
109
110static void xlp_pic_unmask(struct irq_data *d)
111{
112 void *hd = irq_data_get_irq_handler_data(d);
Jayachandran C77ae7982012-10-31 12:01:39 +0000113 struct nlm_soc_info *nodep;
Jayachandran C0c965402011-11-11 17:08:29 +0530114 int irt;
115
Jayachandran C77ae7982012-10-31 12:01:39 +0000116 nodep = nlm_current_node();
Jayachandran C0c965402011-11-11 17:08:29 +0530117 irt = nlm_irq_to_irt(d->irq);
118 if (irt == -1)
119 return;
120
121 if (hd) {
122 void (*extra_ack)(void *) = hd;
123 extra_ack(d);
124 }
125 /* Ack is a single write, no need to lock */
Jayachandran C77ae7982012-10-31 12:01:39 +0000126 nlm_pic_ack(nodep->picbase, irt);
Jayachandran C0c965402011-11-11 17:08:29 +0530127}
128
129static struct irq_chip xlp_pic = {
130 .name = "XLP-PIC",
131 .irq_enable = xlp_pic_enable,
132 .irq_disable = xlp_pic_disable,
133 .irq_mask_ack = xlp_pic_mask_ack,
134 .irq_unmask = xlp_pic_unmask,
135};
136
137static void cpuintr_disable(struct irq_data *d)
138{
139 uint64_t eimr;
140 uint64_t mask = 1ull << d->irq;
141
142 eimr = read_c0_eimr();
143 write_c0_eimr(eimr & ~mask);
144}
145
146static void cpuintr_enable(struct irq_data *d)
147{
148 uint64_t eimr;
149 uint64_t mask = 1ull << d->irq;
150
151 eimr = read_c0_eimr();
152 write_c0_eimr(eimr | mask);
153}
154
155static void cpuintr_ack(struct irq_data *d)
156{
157 uint64_t mask = 1ull << d->irq;
158
159 write_c0_eirr(mask);
160}
161
162static void cpuintr_nop(struct irq_data *d)
163{
164 WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq);
165}
166
167/*
168 * Chip definition for CPU originated interrupts(timer, msg) and
169 * IPIs
170 */
171struct irq_chip nlm_cpu_intr = {
172 .name = "XLP-CPU-INTR",
173 .irq_enable = cpuintr_enable,
174 .irq_disable = cpuintr_disable,
175 .irq_mask = cpuintr_nop,
176 .irq_ack = cpuintr_nop,
177 .irq_eoi = cpuintr_ack,
178};
179
180void __init init_nlm_common_irqs(void)
181{
182 int i, irq, irt;
Jayachandran C77ae7982012-10-31 12:01:39 +0000183 uint64_t irqmask;
184 struct nlm_soc_info *nodep;
Jayachandran C0c965402011-11-11 17:08:29 +0530185
Jayachandran C77ae7982012-10-31 12:01:39 +0000186 nodep = nlm_current_node();
187 irqmask = (1ULL << IRQ_TIMER);
Jayachandran C0c965402011-11-11 17:08:29 +0530188 for (i = 0; i < PIC_IRT_FIRST_IRQ; i++)
189 irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq);
190
191 for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ ; i++)
192 irq_set_chip_and_handler(i, &xlp_pic, handle_level_irq);
193
194#ifdef CONFIG_SMP
195 irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
196 nlm_smp_function_ipi_handler);
197 irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
198 nlm_smp_resched_ipi_handler);
Jayachandran C77ae7982012-10-31 12:01:39 +0000199 irqmask |=
Jayachandran C0c965402011-11-11 17:08:29 +0530200 ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE));
201#endif
202
203 for (irq = PIC_IRT_FIRST_IRQ; irq <= PIC_IRT_LAST_IRQ; irq++) {
204 irt = nlm_irq_to_irt(irq);
205 if (irt == -1)
206 continue;
Jayachandran C77ae7982012-10-31 12:01:39 +0000207 irqmask |= (1ULL << irq);
208 nlm_pic_init_irt(nodep->picbase, irt, irq, 0);
Jayachandran C0c965402011-11-11 17:08:29 +0530209 }
210
Jayachandran C77ae7982012-10-31 12:01:39 +0000211 nodep->irqmask = irqmask;
Jayachandran C0c965402011-11-11 17:08:29 +0530212}
213
214void __init arch_init_irq(void)
215{
216 /* Initialize the irq descriptors */
217 init_nlm_common_irqs();
218
Jayachandran C77ae7982012-10-31 12:01:39 +0000219 write_c0_eimr(nlm_current_node()->irqmask);
Jayachandran C0c965402011-11-11 17:08:29 +0530220}
221
222void __cpuinit nlm_smp_irq_init(void)
223{
224 /* set interrupt mask for non-zero cpus */
Jayachandran C77ae7982012-10-31 12:01:39 +0000225 write_c0_eimr(nlm_current_node()->irqmask);
Jayachandran C0c965402011-11-11 17:08:29 +0530226}
227
228asmlinkage void plat_irq_dispatch(void)
229{
230 uint64_t eirr;
Jayachandran C77ae7982012-10-31 12:01:39 +0000231 int i, node;
Jayachandran C0c965402011-11-11 17:08:29 +0530232
Jayachandran C77ae7982012-10-31 12:01:39 +0000233 node = nlm_nodeid();
Jayachandran C0c965402011-11-11 17:08:29 +0530234 eirr = read_c0_eirr() & read_c0_eimr();
235 if (eirr & (1 << IRQ_TIMER)) {
236 do_IRQ(IRQ_TIMER);
237 return;
238 }
Jayachandran C77ae7982012-10-31 12:01:39 +0000239#ifdef CONFIG_SMP
240 if (eirr & IRQ_IPI_SMP_FUNCTION) {
241 do_IRQ(IRQ_IPI_SMP_FUNCTION);
242 return;
243 }
244 if (eirr & IRQ_IPI_SMP_RESCHEDULE) {
245 do_IRQ(IRQ_IPI_SMP_RESCHEDULE);
246 return;
247 }
248#endif
Jayachandran C0c965402011-11-11 17:08:29 +0530249 i = __ilog2_u64(eirr);
250 if (i == -1)
251 return;
252
Jayachandran C77ae7982012-10-31 12:01:39 +0000253 do_IRQ(nlm_irq_to_xirq(node, i));
Jayachandran C0c965402011-11-11 17:08:29 +0530254}