Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas...
[linux-2.6.git] / arch / mips / netlogic / xlr / irq.c
1 /*
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
42 #include <asm/mipsregs.h>
43
44 #include <asm/netlogic/xlr/iomap.h>
45 #include <asm/netlogic/xlr/pic.h>
46 #include <asm/netlogic/xlr/xlr.h>
47
48 #include <asm/netlogic/interrupt.h>
49 #include <asm/netlogic/mips-extns.h>
50
51 static u64 nlm_irq_mask;
52 static DEFINE_SPINLOCK(nlm_pic_lock);
53
54 static void xlr_pic_enable(struct irq_data *d)
55 {
56         nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
57         unsigned long flags;
58         nlm_reg_t reg;
59         int irq = d->irq;
60
61         WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
62
63         spin_lock_irqsave(&nlm_pic_lock, flags);
64         reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
65         netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
66                           reg | (1 << 6) | (1 << 30) | (1 << 31));
67         spin_unlock_irqrestore(&nlm_pic_lock, flags);
68 }
69
70 static void xlr_pic_mask(struct irq_data *d)
71 {
72         nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
73         unsigned long flags;
74         nlm_reg_t reg;
75         int irq = d->irq;
76
77         WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
78
79         spin_lock_irqsave(&nlm_pic_lock, flags);
80         reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
81         netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
82                           reg | (1 << 6) | (1 << 30) | (0 << 31));
83         spin_unlock_irqrestore(&nlm_pic_lock, flags);
84 }
85
86 #ifdef CONFIG_PCI
87 /* Extra ACK needed for XLR on chip PCI controller */
88 static void xlr_pci_ack(struct irq_data *d)
89 {
90         nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET);
91
92         netlogic_read_reg(pci_mmio, (0x140 >> 2));
93 }
94
95 /* Extra ACK needed for XLS on chip PCIe controller */
96 static void xls_pcie_ack(struct irq_data *d)
97 {
98         nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
99
100         switch (d->irq) {
101         case PIC_PCIE_LINK0_IRQ:
102                 netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
103                 break;
104         case PIC_PCIE_LINK1_IRQ:
105                 netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
106                 break;
107         case PIC_PCIE_LINK2_IRQ:
108                 netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
109                 break;
110         case PIC_PCIE_LINK3_IRQ:
111                 netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
112                 break;
113         }
114 }
115
116 /* For XLS B silicon, the 3,4 PCI interrupts are different */
117 static void xls_pcie_ack_b(struct irq_data *d)
118 {
119         nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
120
121         switch (d->irq) {
122         case PIC_PCIE_LINK0_IRQ:
123                 netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
124                 break;
125         case PIC_PCIE_LINK1_IRQ:
126                 netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
127                 break;
128         case PIC_PCIE_XLSB0_LINK2_IRQ:
129                 netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
130                 break;
131         case PIC_PCIE_XLSB0_LINK3_IRQ:
132                 netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
133                 break;
134         }
135 }
136 #endif
137
138 static void xlr_pic_ack(struct irq_data *d)
139 {
140         unsigned long flags;
141         nlm_reg_t *mmio;
142         int irq = d->irq;
143         void *hd = irq_data_get_irq_handler_data(d);
144
145         WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
146
147         if (hd) {
148                 void (*extra_ack)(void *) = hd;
149                 extra_ack(d);
150         }
151         mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
152         spin_lock_irqsave(&nlm_pic_lock, flags);
153         netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE)));
154         spin_unlock_irqrestore(&nlm_pic_lock, flags);
155 }
156
157 /*
158  * This chip definition handles interrupts routed thru the XLR
159  * hardware PIC, currently IRQs 8-39 are mapped to hardware intr
160  * 0-31 wired the XLR PIC
161  */
162 static struct irq_chip xlr_pic = {
163         .name           = "XLR-PIC",
164         .irq_enable     = xlr_pic_enable,
165         .irq_mask       = xlr_pic_mask,
166         .irq_ack        = xlr_pic_ack,
167 };
168
169 static void rsvd_irq_handler(struct irq_data *d)
170 {
171         WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq);
172 }
173
174 /*
175  * Chip definition for CPU originated interrupts(timer, msg) and
176  * IPIs
177  */
178 struct irq_chip nlm_cpu_intr = {
179         .name           = "XLR-CPU-INTR",
180         .irq_enable     = rsvd_irq_handler,
181         .irq_mask       = rsvd_irq_handler,
182         .irq_ack        = rsvd_irq_handler,
183 };
184
185 void __init init_xlr_irqs(void)
186 {
187         nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
188         uint32_t thread_mask = 1;
189         int level, i;
190
191         pr_info("Interrupt thread mask [%x]\n", thread_mask);
192         for (i = 0; i < PIC_NUM_IRTS; i++) {
193                 level = PIC_IRQ_IS_EDGE_TRIGGERED(i);
194
195                 /* Bind all PIC irqs to boot cpu */
196                 netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask);
197
198                 /*
199                  * Use local scheduling and high polarity for all IRTs
200                  * Invalidate all IRTs, by default
201                  */
202                 netlogic_write_reg(mmio, PIC_IRT_1_BASE + i,
203                                 (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i));
204         }
205
206         /* Make all IRQs as level triggered by default */
207         for (i = 0; i < NR_IRQS; i++) {
208                 if (PIC_IRQ_IS_IRT(i))
209                         irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq);
210                 else
211                         irq_set_chip_and_handler(i, &nlm_cpu_intr,
212                                                 handle_level_irq);
213         }
214 #ifdef CONFIG_SMP
215         irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
216                          nlm_smp_function_ipi_handler);
217         irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
218                          nlm_smp_resched_ipi_handler);
219         nlm_irq_mask |=
220             ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE));
221 #endif
222
223 #ifdef CONFIG_PCI
224         /*
225          * For PCI interrupts, we need to ack the PIC controller too, overload
226          * irq handler data to do this
227          */
228         if (nlm_chip_is_xls()) {
229                 if (nlm_chip_is_xls_b()) {
230                         irq_set_handler_data(PIC_PCIE_LINK0_IRQ,
231                                                         xls_pcie_ack_b);
232                         irq_set_handler_data(PIC_PCIE_LINK1_IRQ,
233                                                         xls_pcie_ack_b);
234                         irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ,
235                                                         xls_pcie_ack_b);
236                         irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ,
237                                                         xls_pcie_ack_b);
238                 } else {
239                         irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack);
240                         irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack);
241                         irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack);
242                         irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack);
243                 }
244         } else {
245                 /* XLR PCI controller ACK */
246                 irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
247         }
248 #endif
249         /* unmask all PIC related interrupts. If no handler is installed by the
250          * drivers, it'll just ack the interrupt and return
251          */
252         for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++)
253                 nlm_irq_mask |= (1ULL << i);
254
255         nlm_irq_mask |= (1ULL << IRQ_TIMER);
256 }
257
258 void __init arch_init_irq(void)
259 {
260         /* Initialize the irq descriptors */
261         init_xlr_irqs();
262         write_c0_eimr(nlm_irq_mask);
263 }
264
265 void __cpuinit nlm_smp_irq_init(void)
266 {
267         /* set interrupt mask for non-zero cpus */
268         write_c0_eimr(nlm_irq_mask);
269 }
270
271 asmlinkage void plat_irq_dispatch(void)
272 {
273         uint64_t eirr;
274         int i;
275
276         eirr = read_c0_eirr() & read_c0_eimr();
277         if (!eirr)
278                 return;
279
280         /* no need of EIRR here, writing compare clears interrupt */
281         if (eirr & (1 << IRQ_TIMER)) {
282                 do_IRQ(IRQ_TIMER);
283                 return;
284         }
285
286         /* use dcltz: optimize below code */
287         for (i = 63; i != -1; i--) {
288                 if (eirr & (1ULL << i))
289                         break;
290         }
291         if (i == -1) {
292                 pr_err("no interrupt !!\n");
293                 return;
294         }
295
296         /* Ack eirr */
297         write_c0_eirr(1ULL << i);
298
299         do_IRQ(i);
300 }