loongson_intr.c revision 1.1 1 1.1 bouyer /* $NetBSD: loongson_intr.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $ */
2 1.1 bouyer
3 1.1 bouyer /*-
4 1.1 bouyer * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 1.1 bouyer * All rights reserved.
6 1.1 bouyer *
7 1.1 bouyer * This code is derived from software contributed to The NetBSD Foundation
8 1.1 bouyer * by Jason R. Thorpe.
9 1.1 bouyer *
10 1.1 bouyer * Redistribution and use in source and binary forms, with or without
11 1.1 bouyer * modification, are permitted provided that the following conditions
12 1.1 bouyer * are met:
13 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
14 1.1 bouyer * notice, this list of conditions and the following disclaimer.
15 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
17 1.1 bouyer * documentation and/or other materials provided with the distribution.
18 1.1 bouyer *
19 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 bouyer * POSSIBILITY OF SUCH DAMAGE.
30 1.1 bouyer */
31 1.1 bouyer
32 1.1 bouyer #include <sys/cdefs.h>
33 1.1 bouyer __KERNEL_RCSID(0, "$NetBSD: loongson_intr.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");
34 1.1 bouyer
35 1.1 bouyer #define __INTR_PRIVATE
36 1.1 bouyer
37 1.1 bouyer #include <sys/param.h>
38 1.1 bouyer #include <sys/device.h>
39 1.1 bouyer #include <sys/cpu.h>
40 1.1 bouyer #include <sys/intr.h>
41 1.1 bouyer #include <sys/bus.h>
42 1.1 bouyer #include <sys/malloc.h>
43 1.1 bouyer
44 1.1 bouyer #include <mips/mips3_clock.h>
45 1.1 bouyer #include <machine/locore.h>
46 1.1 bouyer
47 1.1 bouyer #include <evbmips/loongson/autoconf.h>
48 1.1 bouyer #include <evbmips/loongson/loongson_intr.h>
49 1.1 bouyer
50 1.1 bouyer #include <mips/locore.h>
51 1.1 bouyer
52 1.1 bouyer #include <mips/bonito/bonitoreg.h>
53 1.1 bouyer #include <mips/bonito/bonitovar.h>
54 1.1 bouyer
55 1.1 bouyer #include <dev/pci/pciidereg.h>
56 1.1 bouyer #include <dev/isa/isavar.h>
57 1.1 bouyer
58 1.1 bouyer #include "isa.h"
59 1.1 bouyer
60 1.1 bouyer #ifdef INTR_DEBUG
61 1.1 bouyer #define DPRINTF(x) printf x
62 1.1 bouyer #else
63 1.1 bouyer #define DPRINTF(x)
64 1.1 bouyer #endif
65 1.1 bouyer
66 1.1 bouyer struct bonito_intrhead bonito_intrhead[BONITO_NINTS];
67 1.1 bouyer
68 1.1 bouyer /*
69 1.1 bouyer * This is a mask of bits to clear in the SR when we go to a
70 1.1 bouyer * given hardware interrupt priority level.
71 1.1 bouyer */
72 1.1 bouyer static const struct ipl_sr_map loongson_ipl_sr_map = {
73 1.1 bouyer .sr_bits = {
74 1.1 bouyer [IPL_NONE] = 0,
75 1.1 bouyer [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
76 1.1 bouyer [IPL_SOFTNET] = MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1,
77 1.1 bouyer [IPL_VM] =
78 1.1 bouyer MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
79 1.1 bouyer MIPS_INT_MASK_0 |
80 1.1 bouyer MIPS_INT_MASK_1 |
81 1.1 bouyer MIPS_INT_MASK_2 |
82 1.1 bouyer MIPS_INT_MASK_3 |
83 1.1 bouyer MIPS_INT_MASK_4,
84 1.1 bouyer [IPL_SCHED] =
85 1.1 bouyer MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
86 1.1 bouyer MIPS_INT_MASK_0 |
87 1.1 bouyer MIPS_INT_MASK_1 |
88 1.1 bouyer MIPS_INT_MASK_2 |
89 1.1 bouyer MIPS_INT_MASK_3 |
90 1.1 bouyer MIPS_INT_MASK_4 |
91 1.1 bouyer MIPS_INT_MASK_5,
92 1.1 bouyer [IPL_DDB] = MIPS_INT_MASK,
93 1.1 bouyer [IPL_HIGH] = MIPS_INT_MASK,
94 1.1 bouyer },
95 1.1 bouyer };
96 1.1 bouyer
97 1.1 bouyer
98 1.1 bouyer void
99 1.1 bouyer evbmips_intr_init(void)
100 1.1 bouyer {
101 1.1 bouyer const struct bonito_config * const bc = sys_platform->bonito_config;
102 1.1 bouyer const struct bonito_irqmap *irqmap;
103 1.1 bouyer int i;
104 1.1 bouyer
105 1.1 bouyer ipl_sr_map = loongson_ipl_sr_map;
106 1.1 bouyer
107 1.1 bouyer for (i = 0; i < BONITO_NDIRECT; i++) {
108 1.1 bouyer irqmap = &sys_platform->irq_map[i];
109 1.1 bouyer if (irqmap->name == NULL)
110 1.1 bouyer continue;
111 1.1 bouyer DPRINTF(("attach %d %s\n", i, irqmap->name));
112 1.1 bouyer evcnt_attach_dynamic(&bonito_intrhead[i].intr_count,
113 1.1 bouyer EVCNT_TYPE_INTR, NULL, "bonito", irqmap->name);
114 1.1 bouyer LIST_INIT(&bonito_intrhead[i].intrhand_head);
115 1.1 bouyer }
116 1.1 bouyer
117 1.1 bouyer REGVAL(BONITO_GPIOIE) = bc->bc_gpioIE;
118 1.1 bouyer REGVAL(BONITO_INTEDGE) = bc->bc_intEdge;
119 1.1 bouyer /* REGVAL(BONITO_INTSTEER) = bc->bc_intSteer; XXX */
120 1.1 bouyer REGVAL(BONITO_INTPOL) = bc->bc_intPol;
121 1.1 bouyer REGVAL(BONITO_INTENCLR) = 0xffffffff;
122 1.1 bouyer (void)REGVAL(BONITO_INTENCLR);
123 1.1 bouyer
124 1.1 bouyer if (sys_platform->isa_chipset != NULL) {
125 1.1 bouyer int irq;
126 1.1 bouyer static char irqstr[8];
127 1.1 bouyer for (irq = 0; irq < BONITO_NISA; irq++) {
128 1.1 bouyer i = BONITO_ISA_IRQ(irq);
129 1.1 bouyer sprintf(irqstr, "irq %d", irq);
130 1.1 bouyer DPRINTF(("attach %d %d %s\n", i, irq, irqstr));
131 1.1 bouyer evcnt_attach_dynamic(&bonito_intrhead[i].intr_count,
132 1.1 bouyer EVCNT_TYPE_INTR, NULL, "isa", irqstr);
133 1.1 bouyer LIST_INIT(&bonito_intrhead[i].intrhand_head);
134 1.1 bouyer }
135 1.1 bouyer }
136 1.1 bouyer }
137 1.1 bouyer
138 1.1 bouyer void
139 1.1 bouyer evbmips_iointr(int ppl, vaddr_t pc, uint32_t ipending)
140 1.1 bouyer {
141 1.1 bouyer struct evbmips_intrhand *ih;
142 1.1 bouyer int irq;
143 1.1 bouyer uint32_t isr0, isr, imr;
144 1.1 bouyer
145 1.1 bouyer /*
146 1.1 bouyer * Read the interrupt pending registers, mask them with the
147 1.1 bouyer * ones we have enabled, and service them in order of decreasing
148 1.1 bouyer * priority.
149 1.1 bouyer */
150 1.1 bouyer isr0 = REGVAL(BONITO_INTISR);
151 1.1 bouyer imr = REGVAL(BONITO_INTEN);
152 1.1 bouyer
153 1.1 bouyer if (ipending & sys_platform->bonito_mips_intr) {
154 1.1 bouyer isr = isr0 & imr & LOONGSON_INTRMASK_LVL4;
155 1.1 bouyer
156 1.1 bouyer REGVAL(BONITO_INTENCLR) = isr;
157 1.1 bouyer (void)REGVAL(BONITO_INTENCLR);
158 1.1 bouyer
159 1.1 bouyer for (irq = 0; irq < BONITO_NINTS; irq++) {
160 1.1 bouyer if ((isr & (1 << irq)) == 0)
161 1.1 bouyer continue;
162 1.1 bouyer bonito_intrhead[irq].intr_count.ev_count++;
163 1.1 bouyer LIST_FOREACH (ih,
164 1.1 bouyer &bonito_intrhead[irq].intrhand_head, ih_q) {
165 1.1 bouyer (*ih->ih_func)(ih->ih_arg);
166 1.1 bouyer }
167 1.1 bouyer }
168 1.1 bouyer REGVAL(BONITO_INTENSET) = isr;
169 1.1 bouyer (void)REGVAL(BONITO_INTENSET);
170 1.1 bouyer }
171 1.1 bouyer if (isr0 & LOONGSON_INTRMASK_INT0)
172 1.1 bouyer sys_platform->isa_intr(ppl, pc, ipending);
173 1.1 bouyer }
174 1.1 bouyer
175 1.1 bouyer void *
176 1.1 bouyer loongson_pciide_compat_intr_establish(void *v, struct device *dev,
177 1.1 bouyer const struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
178 1.1 bouyer {
179 1.1 bouyer pci_chipset_tag_t pc = pa->pa_pc;
180 1.1 bouyer void *cookie;
181 1.1 bouyer int bus, irq;
182 1.1 bouyer
183 1.1 bouyer pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
184 1.1 bouyer
185 1.1 bouyer /*
186 1.1 bouyer * If this isn't PCI bus #0, all bets are off.
187 1.1 bouyer */
188 1.1 bouyer if (bus != 0)
189 1.1 bouyer return (NULL);
190 1.1 bouyer
191 1.1 bouyer irq = PCIIDE_COMPAT_IRQ(chan);
192 1.1 bouyer #if NISA > 0
193 1.1 bouyer if (sys_platform->isa_chipset != NULL)
194 1.1 bouyer cookie = isa_intr_establish(sys_platform->isa_chipset, irq,
195 1.1 bouyer IST_EDGE, IPL_BIO, func, arg);
196 1.1 bouyer else
197 1.1 bouyer #endif
198 1.1 bouyer cookie = NULL;
199 1.1 bouyer if (cookie == NULL)
200 1.1 bouyer return (NULL);
201 1.1 bouyer printf("%s: %s channel interrupting at %s\n", dev->dv_xname,
202 1.1 bouyer PCIIDE_CHANNEL_NAME(chan),
203 1.1 bouyer isa_intr_string(sys_platform->isa_chipset, irq));
204 1.1 bouyer return (cookie);
205 1.1 bouyer }
206 1.1 bouyer
207 1.1 bouyer int
208 1.1 bouyer loongson_pci_intr_map(const struct pci_attach_args *pa,
209 1.1 bouyer pci_intr_handle_t *ihp)
210 1.1 bouyer {
211 1.1 bouyer pcitag_t bustag = pa->pa_intrtag;
212 1.1 bouyer int buspin = pa->pa_intrpin;
213 1.1 bouyer pci_chipset_tag_t pc = pa->pa_pc;
214 1.1 bouyer int device, function;
215 1.1 bouyer
216 1.1 bouyer if (buspin == 0) {
217 1.1 bouyer /* No IRQ used. */
218 1.1 bouyer return (1);
219 1.1 bouyer }
220 1.1 bouyer
221 1.1 bouyer if (buspin > 4) {
222 1.1 bouyer printf("loongson_pci_intr_map: bad interrupt pin %d\n",
223 1.1 bouyer buspin);
224 1.1 bouyer return (1);
225 1.1 bouyer }
226 1.1 bouyer
227 1.1 bouyer pci_decompose_tag(pc, bustag, NULL, &device, &function);
228 1.1 bouyer return (sys_platform->p_pci_intr_map(device, function, buspin, ihp));
229 1.1 bouyer }
230 1.1 bouyer
231 1.1 bouyer const char *
232 1.1 bouyer loongson_pci_intr_string(void *v, pci_intr_handle_t ih)
233 1.1 bouyer {
234 1.1 bouyer
235 1.1 bouyer const struct bonito_config *bc = v;
236 1.1 bouyer return loongson_intr_string(bc, ih);
237 1.1 bouyer }
238 1.1 bouyer
239 1.1 bouyer const struct evcnt *
240 1.1 bouyer loongson_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
241 1.1 bouyer {
242 1.1 bouyer
243 1.1 bouyer return &bonito_intrhead[ih].intr_count;
244 1.1 bouyer }
245 1.1 bouyer
246 1.1 bouyer void *
247 1.1 bouyer loongson_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
248 1.1 bouyer int (*func)(void *), void *arg)
249 1.1 bouyer {
250 1.1 bouyer if (BONITO_IRQ_IS_ISA(ih)) {
251 1.1 bouyer if (sys_platform->isa_chipset == NULL)
252 1.1 bouyer panic("ISA interrupt on non-ISA platform");
253 1.1 bouyer return sys_platform->isa_chipset->ic_intr_establish(v,
254 1.1 bouyer BONITO_IRQ_TO_ISA(ih), IST_EDGE, level, func, arg);
255 1.1 bouyer }
256 1.1 bouyer return evbmips_intr_establish(ih, func, arg);
257 1.1 bouyer }
258 1.1 bouyer
259 1.1 bouyer void
260 1.1 bouyer loongson_pci_intr_disestablish(void *v, void *cookie)
261 1.1 bouyer {
262 1.1 bouyer struct evbmips_intrhand *ih = cookie;
263 1.1 bouyer if (BONITO_IRQ_IS_ISA(ih->ih_irq)) {
264 1.1 bouyer if (sys_platform->isa_chipset == NULL)
265 1.1 bouyer panic("ISA interrupt on non-ISA platform");
266 1.1 bouyer sys_platform->isa_chipset->ic_intr_disestablish(v, ih);
267 1.1 bouyer return;
268 1.1 bouyer }
269 1.1 bouyer return (evbmips_intr_disestablish(cookie));
270 1.1 bouyer }
271 1.1 bouyer
272 1.1 bouyer void
273 1.1 bouyer loongson_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
274 1.1 bouyer int *iline)
275 1.1 bouyer {
276 1.1 bouyer
277 1.1 bouyer /*
278 1.1 bouyer * We actually don't need to do anything; everything is handled
279 1.1 bouyer * in pci_intr_map().
280 1.1 bouyer */
281 1.1 bouyer *iline = 0;
282 1.1 bouyer }
283 1.1 bouyer
284 1.1 bouyer
285 1.1 bouyer void *
286 1.1 bouyer evbmips_intr_establish(int irq, int (*func)(void *), void *arg)
287 1.1 bouyer {
288 1.1 bouyer struct evbmips_intrhand *ih;
289 1.1 bouyer int s;
290 1.1 bouyer
291 1.1 bouyer KASSERT(irq < BONITO_NINTS);
292 1.1 bouyer DPRINTF(("loongson_intr_establish %d %p", irq, func));
293 1.1 bouyer
294 1.1 bouyer ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT|M_ZERO);
295 1.1 bouyer if (ih == NULL)
296 1.1 bouyer return NULL;
297 1.1 bouyer
298 1.1 bouyer ih->ih_func = func;
299 1.1 bouyer ih->ih_arg = arg;
300 1.1 bouyer ih->ih_irq = irq;
301 1.1 bouyer DPRINTF((" ih %p", ih));
302 1.1 bouyer
303 1.1 bouyer /* link it into tables */
304 1.1 bouyer s = splhigh();
305 1.1 bouyer LIST_INSERT_HEAD(&bonito_intrhead[irq].intrhand_head, ih, ih_q);
306 1.1 bouyer /* and enable it */
307 1.1 bouyer DPRINTF((" inten 0x%x", REGVAL(BONITO_INTEN)));
308 1.1 bouyer if (bonito_intrhead[irq].refcnt++ == 0 && !BONITO_IRQ_IS_ISA(irq))
309 1.1 bouyer REGVAL(BONITO_INTENSET) = (1 << ih->ih_irq);
310 1.1 bouyer DPRINTF((" now 0x%x\n", REGVAL(BONITO_INTEN)));
311 1.1 bouyer splx(s);
312 1.1 bouyer
313 1.1 bouyer return (ih);
314 1.1 bouyer }
315 1.1 bouyer
316 1.1 bouyer void
317 1.1 bouyer evbmips_intr_disestablish(void *cookie)
318 1.1 bouyer {
319 1.1 bouyer struct evbmips_intrhand *ih = cookie;
320 1.1 bouyer int s;
321 1.1 bouyer
322 1.1 bouyer s = splhigh();
323 1.1 bouyer LIST_REMOVE(ih, ih_q);
324 1.1 bouyer bonito_intrhead[ih->ih_irq].refcnt--;
325 1.1 bouyer if (bonito_intrhead[ih->ih_irq].refcnt == 0 &&
326 1.1 bouyer !BONITO_IRQ_IS_ISA(ih->ih_irq))
327 1.1 bouyer REGVAL(BONITO_INTENCLR) = (1 << ih->ih_irq);
328 1.1 bouyer splx(s);
329 1.1 bouyer free(ih, M_DEVBUF);
330 1.1 bouyer }
331 1.1 bouyer
332 1.1 bouyer const char *
333 1.1 bouyer loongson_intr_string(const struct bonito_config *bc, int irq)
334 1.1 bouyer {
335 1.1 bouyer static char irqstr[12]; /* 8 + 2 + NULL + sanity */
336 1.1 bouyer if (BONITO_IRQ_IS_ISA(irq)) {
337 1.1 bouyer sprintf(irqstr, "isa irq %d", BONITO_IRQ_TO_ISA(irq));
338 1.1 bouyer return irqstr;
339 1.1 bouyer }
340 1.1 bouyer return sys_platform->irq_map[irq].name;
341 1.1 bouyer }
342