Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/netlogic/xlr/irq.c
10821 views
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
}
301
302