pcib.c revision 1.9 1 1.9 kleink /* $NetBSD: pcib.c,v 1.9 2004/04/24 15:49:00 kleink Exp $ */
2 1.1 simonb
3 1.1 simonb /*
4 1.1 simonb * Copyright 2002 Wasabi Systems, Inc.
5 1.1 simonb * All rights reserved.
6 1.1 simonb *
7 1.1 simonb * Written by Simon Burge for Wasabi Systems, Inc.
8 1.1 simonb *
9 1.1 simonb * Redistribution and use in source and binary forms, with or without
10 1.1 simonb * modification, are permitted provided that the following conditions
11 1.1 simonb * are met:
12 1.1 simonb * 1. Redistributions of source code must retain the above copyright
13 1.1 simonb * notice, this list of conditions and the following disclaimer.
14 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 simonb * notice, this list of conditions and the following disclaimer in the
16 1.1 simonb * documentation and/or other materials provided with the distribution.
17 1.1 simonb * 3. All advertising materials mentioning features or use of this software
18 1.1 simonb * must display the following acknowledgement:
19 1.1 simonb * This product includes software developed for the NetBSD Project by
20 1.1 simonb * Wasabi Systems, Inc.
21 1.1 simonb * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.1 simonb * or promote products derived from this software without specific prior
23 1.1 simonb * written permission.
24 1.1 simonb *
25 1.1 simonb * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.1 simonb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.1 simonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.1 simonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.1 simonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.1 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.1 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.1 simonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.1 simonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.1 simonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.1 simonb * POSSIBILITY OF SUCH DAMAGE.
36 1.1 simonb */
37 1.8 lukem
38 1.8 lukem #include <sys/cdefs.h>
39 1.9 kleink __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.9 2004/04/24 15:49:00 kleink Exp $");
40 1.1 simonb
41 1.1 simonb #include <sys/param.h>
42 1.1 simonb #include <sys/systm.h>
43 1.1 simonb #include <sys/kernel.h>
44 1.1 simonb #include <sys/device.h>
45 1.1 simonb #include <sys/malloc.h>
46 1.1 simonb
47 1.1 simonb #include <machine/bus.h>
48 1.1 simonb #include <evbmips/malta/maltareg.h>
49 1.1 simonb #include <evbmips/malta/maltavar.h>
50 1.1 simonb #include <evbmips/malta/dev/gtreg.h>
51 1.1 simonb #include <evbmips/malta/pci/pcibvar.h>
52 1.1 simonb
53 1.1 simonb #include <dev/isa/isareg.h>
54 1.1 simonb #include <dev/isa/isavar.h>
55 1.1 simonb
56 1.1 simonb #include <dev/pci/pcireg.h>
57 1.1 simonb #include <dev/pci/pcivar.h>
58 1.1 simonb #include <dev/pci/pcidevs.h>
59 1.1 simonb
60 1.1 simonb #include <dev/ic/i8259reg.h>
61 1.1 simonb
62 1.1 simonb
63 1.1 simonb #define ICU_LEN 16 /* number of ISA IRQs */
64 1.1 simonb
65 1.1 simonb const char *isa_intrnames[ICU_LEN] = {
66 1.1 simonb "timer",
67 1.1 simonb "keyboard",
68 1.1 simonb "reserved", /* by South Bridge (for cascading) */
69 1.1 simonb "com1",
70 1.1 simonb "com0",
71 1.1 simonb "not used",
72 1.1 simonb "floppy",
73 1.1 simonb "centronics",
74 1.1 simonb "mcclock",
75 1.1 simonb "i2c",
76 1.1 simonb "pci A,B", /* PCI slots 1..4, ethernet */
77 1.1 simonb "pci C,D", /* PCI slots 1..4, audio, usb */
78 1.1 simonb "mouse",
79 1.1 simonb "reserved",
80 1.1 simonb "ide primary",
81 1.1 simonb "ide secondary", /* and compact flash connector */
82 1.1 simonb };
83 1.1 simonb
84 1.1 simonb struct pcib_intrhead {
85 1.1 simonb LIST_HEAD(, evbmips_intrhand) intr_q;
86 1.1 simonb struct evcnt intr_count;
87 1.1 simonb int intr_type;
88 1.1 simonb };
89 1.1 simonb
90 1.1 simonb struct pcib_softc {
91 1.1 simonb struct device sc_dev;
92 1.1 simonb
93 1.1 simonb bus_space_tag_t sc_iot;
94 1.1 simonb bus_space_handle_t sc_ioh_icu1;
95 1.1 simonb bus_space_handle_t sc_ioh_icu2;
96 1.1 simonb bus_space_handle_t sc_ioh_elcr;
97 1.1 simonb
98 1.2 simonb struct mips_isa_chipset sc_ic;
99 1.1 simonb
100 1.1 simonb struct pcib_intrhead sc_intrtab[ICU_LEN];
101 1.1 simonb
102 1.1 simonb u_int16_t sc_imask;
103 1.1 simonb u_int16_t sc_elcr;
104 1.1 simonb
105 1.1 simonb u_int16_t sc_reserved;
106 1.1 simonb
107 1.1 simonb void *sc_ih;
108 1.1 simonb };
109 1.1 simonb
110 1.1 simonb /*
111 1.1 simonb * XXX
112 1.1 simonb * There is only one pci-isa bridge, and all external interrupts
113 1.1 simonb * are routed through it, so we need to remember the softc when
114 1.1 simonb * called from other interrupt handling code.
115 1.1 simonb */
116 1.1 simonb static struct pcib_softc *my_sc;
117 1.2 simonb struct mips_isa_chipset *pcib_ic;
118 1.1 simonb
119 1.1 simonb static int pcib_match(struct device *, struct cfdata *, void *);
120 1.1 simonb static void pcib_attach(struct device *, struct device *, void *);
121 1.1 simonb static int pcib_intr(void *v);
122 1.1 simonb static void pcib_bridge_callback(struct device *);
123 1.1 simonb static int pcib_print(void *, const char *);
124 1.1 simonb static void pcib_set_icus(struct pcib_softc *sc);
125 1.1 simonb static void pcib_cleanup(void *arg);
126 1.1 simonb
127 1.1 simonb static const struct evcnt *
128 1.1 simonb pcib_isa_intr_evcnt(void *, int);
129 1.1 simonb static void *pcib_isa_intr_establish(void *, int, int, int,
130 1.1 simonb int (*)(void *), void *);
131 1.1 simonb static void pcib_isa_intr_disestablish(void *, void *);
132 1.1 simonb static void pcib_isa_attach_hook(struct device *, struct device *,
133 1.1 simonb struct isabus_attach_args *);
134 1.1 simonb static int pcib_isa_intr_alloc(void *, int, int, int *);
135 1.1 simonb static const char *
136 1.1 simonb pcib_isa_intr_string(void *, int);
137 1.1 simonb
138 1.5 thorpej CFATTACH_DECL(pcib, sizeof(struct pcib_softc),
139 1.6 thorpej pcib_match, pcib_attach, NULL, NULL);
140 1.1 simonb
141 1.1 simonb static int
142 1.1 simonb pcib_match(struct device *parent, struct cfdata *match, void *aux)
143 1.1 simonb {
144 1.1 simonb struct pci_attach_args *pa = aux;
145 1.1 simonb
146 1.1 simonb if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
147 1.1 simonb PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
148 1.1 simonb return (1);
149 1.1 simonb
150 1.1 simonb return (0);
151 1.1 simonb }
152 1.1 simonb
153 1.1 simonb static void
154 1.1 simonb pcib_attach(struct device *parent, struct device *self, void *aux)
155 1.1 simonb {
156 1.1 simonb struct pci_attach_args *pa = aux;
157 1.1 simonb char devinfo[256];
158 1.1 simonb int i;
159 1.1 simonb
160 1.1 simonb printf("\n");
161 1.1 simonb
162 1.1 simonb if (my_sc != NULL)
163 1.3 provos panic("pcib_attach: already attached!");
164 1.1 simonb my_sc = (void *)self;
165 1.1 simonb
166 1.1 simonb /*
167 1.1 simonb * Just print out a description and defer configuration
168 1.1 simonb * until all PCI devices have been attached.
169 1.1 simonb */
170 1.9 kleink pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
171 1.1 simonb printf("%s: %s, (rev . 0x%02x)\n", self->dv_xname, devinfo,
172 1.1 simonb PCI_REVISION(pa->pa_class));
173 1.1 simonb
174 1.1 simonb my_sc->sc_iot = pa->pa_iot;
175 1.1 simonb
176 1.1 simonb /*
177 1.1 simonb * Map the PIC/ELCR registers.
178 1.1 simonb */
179 1.1 simonb if (bus_space_map(my_sc->sc_iot, 0x4d0, 2, 0, &my_sc->sc_ioh_elcr) != 0)
180 1.1 simonb printf("%s: unable to map ELCR registers\n",
181 1.1 simonb my_sc->sc_dev.dv_xname);
182 1.1 simonb if (bus_space_map(my_sc->sc_iot, IO_ICU1, 2, 0, &my_sc->sc_ioh_icu1) != 0)
183 1.1 simonb printf("%s: unable to map ICU1 registers\n",
184 1.1 simonb my_sc->sc_dev.dv_xname);
185 1.1 simonb if (bus_space_map(my_sc->sc_iot, IO_ICU2, 2, 0, &my_sc->sc_ioh_icu2) != 0)
186 1.1 simonb printf("%s: unable to map ICU2 registers\n",
187 1.1 simonb my_sc->sc_dev.dv_xname);
188 1.1 simonb
189 1.1 simonb /* All interrupts default to "masked off". */
190 1.1 simonb my_sc->sc_imask = 0xffff;
191 1.1 simonb
192 1.1 simonb /* All interrupts default to edge-triggered. */
193 1.1 simonb my_sc->sc_elcr = 0;
194 1.1 simonb
195 1.1 simonb /*
196 1.1 simonb * Initialize the 8259s.
197 1.1 simonb */
198 1.1 simonb /* reset, program device, 4 bytes */
199 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW1,
200 1.1 simonb ICW1_SELECT | ICW1_IC4);
201 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW2,
202 1.1 simonb ICW2_VECTOR(0)/*XXX*/);
203 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW3,
204 1.1 simonb ICW3_CASCADE(2));
205 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW4,
206 1.1 simonb ICW4_8086);
207 1.1 simonb
208 1.1 simonb /* mask all interrupts */
209 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW1,
210 1.1 simonb my_sc->sc_imask & 0xff);
211 1.1 simonb
212 1.1 simonb /* enable special mask mode */
213 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
214 1.1 simonb OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
215 1.1 simonb
216 1.1 simonb /* read IRR by default */
217 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3,
218 1.1 simonb OCW3_SELECT | OCW3_RR);
219 1.1 simonb
220 1.1 simonb /* reset, program device, 4 bytes */
221 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW1,
222 1.1 simonb ICW1_SELECT | ICW1_IC4);
223 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW2,
224 1.1 simonb ICW2_VECTOR(0)/*XXX*/);
225 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW3,
226 1.1 simonb ICW3_CASCADE(2));
227 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW4,
228 1.1 simonb ICW4_8086);
229 1.1 simonb
230 1.1 simonb /* mask all interrupts */
231 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW1,
232 1.1 simonb my_sc->sc_imask & 0xff);
233 1.1 simonb
234 1.1 simonb /* enable special mask mode */
235 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
236 1.1 simonb OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
237 1.1 simonb
238 1.1 simonb /* read IRR by default */
239 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3,
240 1.1 simonb OCW3_SELECT | OCW3_RR);
241 1.1 simonb
242 1.1 simonb /*
243 1.1 simonb * Default all interrupts to edge-triggered.
244 1.1 simonb */
245 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 0,
246 1.1 simonb my_sc->sc_elcr & 0xff);
247 1.1 simonb bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 1,
248 1.1 simonb (my_sc->sc_elcr >> 8) & 0xff);
249 1.1 simonb
250 1.1 simonb /*
251 1.1 simonb * Some ISA interrupts are reserved for devices that
252 1.1 simonb * we know are hard-wired to certain IRQs.
253 1.1 simonb */
254 1.1 simonb my_sc->sc_reserved =
255 1.1 simonb (1U << 0) | /* timer */
256 1.1 simonb (1U << 1) | /* keyboard controller (keyboard) */
257 1.1 simonb (1U << 2) | /* PIC cascade */
258 1.1 simonb (1U << 3) | /* COM 2 */
259 1.1 simonb (1U << 4) | /* COM 1 */
260 1.1 simonb (1U << 6) | /* floppy */
261 1.1 simonb (1U << 7) | /* centronics */
262 1.1 simonb (1U << 8) | /* RTC */
263 1.1 simonb (1U << 9) | /* I2C */
264 1.1 simonb (1U << 12) | /* keyboard controller (mouse) */
265 1.1 simonb (1U << 14) | /* IDE primary */
266 1.1 simonb (1U << 15); /* IDE secondary */
267 1.1 simonb
268 1.1 simonb /* Set up our ISA chipset. */
269 1.1 simonb my_sc->sc_ic.ic_v = my_sc;
270 1.1 simonb my_sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
271 1.1 simonb my_sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
272 1.1 simonb my_sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
273 1.1 simonb my_sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
274 1.1 simonb my_sc->sc_ic.ic_intr_string = pcib_isa_intr_string;
275 1.1 simonb
276 1.1 simonb pcib_ic = &my_sc->sc_ic; /* XXX for external use */
277 1.1 simonb
278 1.1 simonb /* Initialize our interrupt table. */
279 1.1 simonb for (i = 0; i < ICU_LEN; i++) {
280 1.1 simonb #if 0
281 1.1 simonb char irqstr[8]; /* 4 + 2 + NULL + sanity */
282 1.1 simonb
283 1.1 simonb sprintf(irqstr, "irq %d", i);
284 1.1 simonb evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
285 1.1 simonb EVCNT_TYPE_INTR, NULL, "pcib", irqstr);
286 1.1 simonb #else
287 1.1 simonb evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count,
288 1.1 simonb EVCNT_TYPE_INTR, NULL, "pcib", isa_intrnames[i]);
289 1.1 simonb #endif
290 1.1 simonb LIST_INIT(&my_sc->sc_intrtab[i].intr_q);
291 1.1 simonb my_sc->sc_intrtab[i].intr_type = IST_NONE;
292 1.1 simonb }
293 1.1 simonb
294 1.1 simonb /* Hook up our interrupt handler. */
295 1.1 simonb my_sc->sc_ih = evbmips_intr_establish(MALTA_SOUTHBRIDGE_INTR, pcib_intr, my_sc);
296 1.1 simonb if (my_sc->sc_ih == NULL)
297 1.1 simonb printf("%s: WARNING: unable to register interrupt handler\n",
298 1.1 simonb my_sc->sc_dev.dv_xname);
299 1.1 simonb
300 1.1 simonb
301 1.1 simonb /*
302 1.1 simonb * Disable ISA interrupts before returning to YAMON.
303 1.1 simonb */
304 1.1 simonb if (shutdownhook_establish(pcib_cleanup, my_sc) == NULL)
305 1.1 simonb panic("pcib_attach: could not establish shutdown hook");
306 1.1 simonb
307 1.1 simonb config_defer(self, pcib_bridge_callback);
308 1.1 simonb }
309 1.1 simonb
310 1.1 simonb static void
311 1.1 simonb pcib_bridge_callback(struct device *self)
312 1.1 simonb {
313 1.1 simonb struct pcib_softc *sc = (void *)self;
314 1.1 simonb struct malta_config *mcp = &malta_configuration;
315 1.1 simonb struct isabus_attach_args iba;
316 1.1 simonb
317 1.1 simonb /*
318 1.1 simonb * Attach the ISA bus behind this bridge.
319 1.1 simonb */
320 1.1 simonb memset(&iba, 0, sizeof(iba));
321 1.1 simonb
322 1.1 simonb iba.iba_busname = "isa";
323 1.1 simonb iba.iba_iot = &mcp->mc_iot;
324 1.1 simonb iba.iba_memt = &mcp->mc_memt;
325 1.1 simonb iba.iba_dmat = &mcp->mc_isa_dmat;
326 1.1 simonb
327 1.1 simonb iba.iba_ic = &sc->sc_ic;
328 1.1 simonb iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
329 1.1 simonb
330 1.1 simonb config_found(&sc->sc_dev, &iba, pcib_print);
331 1.1 simonb }
332 1.1 simonb
333 1.1 simonb static int
334 1.1 simonb pcib_print(void *aux, const char *pnp)
335 1.1 simonb {
336 1.1 simonb
337 1.1 simonb /* Only ISAs can attach to pcib's; easy. */
338 1.1 simonb if (pnp)
339 1.7 thorpej aprint_normal("isa at %s", pnp);
340 1.1 simonb return (UNCONF);
341 1.1 simonb }
342 1.1 simonb
343 1.1 simonb static void
344 1.1 simonb pcib_isa_attach_hook(struct device *parent, struct device *self,
345 1.1 simonb struct isabus_attach_args *iba)
346 1.1 simonb {
347 1.1 simonb
348 1.1 simonb /* Nothing to do. */
349 1.1 simonb }
350 1.1 simonb
351 1.1 simonb static void
352 1.1 simonb pcib_set_icus(struct pcib_softc *sc)
353 1.1 simonb {
354 1.1 simonb
355 1.1 simonb /* Enable the cascade IRQ (2) if 8-15 is enabled. */
356 1.1 simonb if ((sc->sc_imask & 0xff00) != 0xff00)
357 1.1 simonb sc->sc_imask &= ~(1U << 2);
358 1.1 simonb else
359 1.1 simonb sc->sc_imask |= (1U << 2);
360 1.1 simonb
361 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
362 1.1 simonb sc->sc_imask & 0xff);
363 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
364 1.1 simonb (sc->sc_imask >> 8) & 0xff);
365 1.1 simonb
366 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
367 1.1 simonb sc->sc_elcr & 0xff);
368 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
369 1.1 simonb (sc->sc_elcr >> 8) & 0xff);
370 1.1 simonb }
371 1.1 simonb
372 1.1 simonb static int
373 1.1 simonb pcib_intr(void *v)
374 1.1 simonb {
375 1.1 simonb struct pcib_softc *sc = v;
376 1.1 simonb struct evbmips_intrhand *ih;
377 1.1 simonb int irq;
378 1.1 simonb
379 1.1 simonb for (;;) {
380 1.1 simonb #if 1
381 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
382 1.1 simonb OCW3_SELECT | OCW3_POLL);
383 1.1 simonb irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
384 1.1 simonb if ((irq & OCW3_POLL_PENDING) == 0)
385 1.1 simonb return (1);
386 1.1 simonb
387 1.1 simonb irq = OCW3_POLL_IRQ(irq);
388 1.1 simonb
389 1.1 simonb if (irq == 2) {
390 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
391 1.1 simonb PIC_OCW3, OCW3_SELECT | OCW3_POLL);
392 1.1 simonb irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
393 1.1 simonb PIC_OCW3);
394 1.1 simonb if (irq & OCW3_POLL_PENDING)
395 1.1 simonb irq = OCW3_POLL_IRQ(irq) + 8;
396 1.1 simonb else
397 1.1 simonb irq = 2;
398 1.1 simonb }
399 1.1 simonb #else
400 1.1 simonb /* XXX - should be a function call to gt.c? */
401 1.1 simonb irq = GT_REGVAL(GT_PCI0_INTR_ACK) & 0xff;
402 1.1 simonb
403 1.1 simonb /*
404 1.1 simonb * From YAMON source code:
405 1.1 simonb *
406 1.1 simonb * IRQ7 is used to detect spurious interrupts.
407 1.1 simonb * The interrupt acknowledge cycle returns IRQ7, if no
408 1.1 simonb * interrupts is requested.
409 1.1 simonb * We can differentiate between this situation and a
410 1.1 simonb * "Normal" IRQ7 by reading the ISR.
411 1.1 simonb */
412 1.1 simonb
413 1.1 simonb if (irq == 7) {
414 1.1 simonb int reg;
415 1.1 simonb
416 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
417 1.1 simonb OCW3_SELECT | OCW3_RR | OCW3_RIS);
418 1.1 simonb reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1,
419 1.1 simonb PIC_OCW3);
420 1.1 simonb if (!(reg & (1 << 7)))
421 1.1 simonb break; /* spurious interrupt */
422 1.1 simonb }
423 1.1 simonb #endif
424 1.1 simonb
425 1.1 simonb sc->sc_intrtab[irq].intr_count.ev_count++;
426 1.1 simonb LIST_FOREACH(ih, &sc->sc_intrtab[irq].intr_q, ih_q)
427 1.1 simonb (*ih->ih_func)(ih->ih_arg);
428 1.1 simonb
429 1.1 simonb /* Send a specific EOI to the 8259. */
430 1.1 simonb if (irq > 7) {
431 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
432 1.1 simonb PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL |
433 1.1 simonb OCW2_ILS(irq & 7));
434 1.1 simonb irq = 2;
435 1.1 simonb }
436 1.1 simonb
437 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
438 1.1 simonb OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq));
439 1.1 simonb }
440 1.1 simonb }
441 1.1 simonb
442 1.1 simonb const char *
443 1.1 simonb pcib_isa_intr_string(void *v, int irq)
444 1.1 simonb {
445 1.1 simonb static char irqstr[12]; /* 8 + 2 + NULL + sanity */
446 1.1 simonb
447 1.1 simonb if (irq == 0 || irq >= ICU_LEN || irq == 2)
448 1.3 provos panic("pcib_isa_intr_string: bogus isa irq 0x%x", irq);
449 1.1 simonb
450 1.1 simonb sprintf(irqstr, "isa irq %d", irq);
451 1.1 simonb return (irqstr);
452 1.1 simonb }
453 1.1 simonb
454 1.1 simonb const struct evcnt *
455 1.1 simonb pcib_isa_intr_evcnt(void *v, int irq)
456 1.1 simonb {
457 1.1 simonb
458 1.1 simonb if (irq == 0 || irq >= ICU_LEN || irq == 2)
459 1.3 provos panic("pcib_isa_intr_evcnt: bogus isa irq 0x%x", irq);
460 1.1 simonb
461 1.1 simonb return (&my_sc->sc_intrtab[irq].intr_count);
462 1.1 simonb }
463 1.1 simonb
464 1.1 simonb void *
465 1.1 simonb pcib_isa_intr_establish(void *v, int irq, int type, int level,
466 1.1 simonb int (*func)(void *), void *arg)
467 1.1 simonb {
468 1.1 simonb struct evbmips_intrhand *ih;
469 1.1 simonb int s;
470 1.1 simonb
471 1.1 simonb if (irq >= ICU_LEN || irq == 2 || type == IST_NONE)
472 1.1 simonb panic("pcib_isa_intr_establish: bad irq or type");
473 1.1 simonb
474 1.1 simonb switch (my_sc->sc_intrtab[irq].intr_type) {
475 1.1 simonb case IST_NONE:
476 1.1 simonb my_sc->sc_intrtab[irq].intr_type = type;
477 1.1 simonb break;
478 1.1 simonb
479 1.1 simonb case IST_EDGE:
480 1.1 simonb case IST_LEVEL:
481 1.1 simonb if (type == my_sc->sc_intrtab[irq].intr_type)
482 1.1 simonb break;
483 1.1 simonb /* FALLTHROUGH */
484 1.1 simonb case IST_PULSE:
485 1.1 simonb /*
486 1.1 simonb * We can't share interrupts in this case.
487 1.1 simonb */
488 1.1 simonb return (NULL);
489 1.1 simonb }
490 1.1 simonb
491 1.1 simonb ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
492 1.1 simonb if (ih == NULL)
493 1.1 simonb return (NULL);
494 1.1 simonb
495 1.1 simonb ih->ih_func = func;
496 1.1 simonb ih->ih_arg = arg;
497 1.1 simonb ih->ih_irq = irq;
498 1.1 simonb
499 1.1 simonb s = splhigh();
500 1.1 simonb
501 1.1 simonb /* Insert the handler into the table. */
502 1.1 simonb LIST_INSERT_HEAD(&my_sc->sc_intrtab[irq].intr_q, ih, ih_q);
503 1.1 simonb my_sc->sc_intrtab[irq].intr_type = type;
504 1.1 simonb
505 1.1 simonb /* Enable it, set trigger mode. */
506 1.1 simonb my_sc->sc_imask &= ~(1 << irq);
507 1.1 simonb if (my_sc->sc_intrtab[irq].intr_type == IST_LEVEL)
508 1.1 simonb my_sc->sc_elcr |= (1 << irq);
509 1.1 simonb else
510 1.1 simonb my_sc->sc_elcr &= ~(1 << irq);
511 1.1 simonb
512 1.1 simonb pcib_set_icus(my_sc);
513 1.1 simonb
514 1.1 simonb splx(s);
515 1.1 simonb
516 1.1 simonb return (ih);
517 1.1 simonb }
518 1.1 simonb
519 1.1 simonb void
520 1.1 simonb pcib_isa_intr_disestablish(void *v, void *arg)
521 1.1 simonb {
522 1.1 simonb struct evbmips_intrhand *ih = arg;
523 1.1 simonb int s;
524 1.1 simonb
525 1.1 simonb s = splhigh();
526 1.1 simonb
527 1.1 simonb LIST_REMOVE(ih, ih_q);
528 1.1 simonb
529 1.1 simonb /* If there are no more handlers on this IRQ, disable it. */
530 1.1 simonb if (LIST_FIRST(&my_sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
531 1.1 simonb my_sc->sc_imask |= (1 << ih->ih_irq);
532 1.1 simonb pcib_set_icus(my_sc);
533 1.1 simonb }
534 1.1 simonb
535 1.1 simonb splx(s);
536 1.1 simonb
537 1.1 simonb free(ih, M_DEVBUF);
538 1.1 simonb }
539 1.1 simonb
540 1.1 simonb static int
541 1.1 simonb pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
542 1.1 simonb {
543 1.1 simonb int i, tmp, bestirq, count;
544 1.1 simonb struct evbmips_intrhand *ih;
545 1.1 simonb
546 1.1 simonb if (type == IST_NONE)
547 1.1 simonb panic("pcib_intr_alloc: bogus type");
548 1.1 simonb
549 1.1 simonb bestirq = -1;
550 1.1 simonb count = -1;
551 1.1 simonb
552 1.1 simonb mask &= ~my_sc->sc_reserved;
553 1.1 simonb
554 1.1 simonb for (i = 0; i < ICU_LEN; i++) {
555 1.1 simonb if ((mask & (1 << i)) == 0)
556 1.1 simonb continue;
557 1.1 simonb
558 1.1 simonb switch (my_sc->sc_intrtab[i].intr_type) {
559 1.1 simonb case IST_NONE:
560 1.1 simonb /*
561 1.1 simonb * If nothing's using the IRQ, just return it.
562 1.1 simonb */
563 1.1 simonb *irq = i;
564 1.1 simonb return (0);
565 1.1 simonb
566 1.1 simonb case IST_EDGE:
567 1.1 simonb case IST_LEVEL:
568 1.1 simonb if (type != my_sc->sc_intrtab[i].intr_type)
569 1.1 simonb continue;
570 1.1 simonb /*
571 1.1 simonb * If the IRQ is sharable, count the number of
572 1.1 simonb * other handlers, and if it's smaller than the
573 1.1 simonb * last IRQ like this, remember it.
574 1.1 simonb */
575 1.1 simonb tmp = 0;
576 1.1 simonb for (ih = LIST_FIRST(&my_sc->sc_intrtab[i].intr_q);
577 1.1 simonb ih != NULL; ih = LIST_NEXT(ih, ih_q))
578 1.1 simonb tmp++;
579 1.1 simonb if (bestirq == -1 || count > tmp) {
580 1.1 simonb bestirq = i;
581 1.1 simonb count = tmp;
582 1.1 simonb }
583 1.1 simonb break;
584 1.1 simonb
585 1.1 simonb case IST_PULSE:
586 1.1 simonb /* This just isn't sharable. */
587 1.1 simonb continue;
588 1.1 simonb }
589 1.1 simonb }
590 1.1 simonb
591 1.1 simonb if (bestirq == -1)
592 1.1 simonb return (1);
593 1.1 simonb
594 1.1 simonb *irq = bestirq;
595 1.1 simonb return (0);
596 1.1 simonb }
597 1.1 simonb
598 1.1 simonb static void
599 1.1 simonb pcib_cleanup(void *arg)
600 1.1 simonb {
601 1.1 simonb
602 1.1 simonb my_sc->sc_imask = 0xffff;
603 1.1 simonb pcib_set_icus(my_sc);
604 1.1 simonb }
605