pcib.c revision 1.12.84.1 1 1.12.84.1 matt /* $NetBSD: pcib.c,v 1.12.84.1 2010/01/10 02:48:45 matt 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.12.84.1 matt __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.12.84.1 2010/01/10 02:48:45 matt 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.12.84.1 matt #include <uvm/uvm_extern.h>
48 1.12.84.1 matt
49 1.1 simonb #include <machine/bus.h>
50 1.1 simonb #include <evbmips/malta/maltareg.h>
51 1.1 simonb #include <evbmips/malta/maltavar.h>
52 1.1 simonb #include <evbmips/malta/dev/gtreg.h>
53 1.1 simonb #include <evbmips/malta/pci/pcibvar.h>
54 1.1 simonb
55 1.1 simonb #include <dev/isa/isareg.h>
56 1.1 simonb #include <dev/isa/isavar.h>
57 1.1 simonb
58 1.1 simonb #include <dev/pci/pcireg.h>
59 1.1 simonb #include <dev/pci/pcivar.h>
60 1.1 simonb #include <dev/pci/pcidevs.h>
61 1.1 simonb
62 1.1 simonb #include <dev/ic/i8259reg.h>
63 1.1 simonb
64 1.1 simonb
65 1.1 simonb #define ICU_LEN 16 /* number of ISA IRQs */
66 1.1 simonb
67 1.12.84.1 matt const char * const isa_intrnames[ICU_LEN] = {
68 1.1 simonb "timer",
69 1.1 simonb "keyboard",
70 1.1 simonb "reserved", /* by South Bridge (for cascading) */
71 1.1 simonb "com1",
72 1.1 simonb "com0",
73 1.1 simonb "not used",
74 1.1 simonb "floppy",
75 1.1 simonb "centronics",
76 1.1 simonb "mcclock",
77 1.1 simonb "i2c",
78 1.1 simonb "pci A,B", /* PCI slots 1..4, ethernet */
79 1.1 simonb "pci C,D", /* PCI slots 1..4, audio, usb */
80 1.1 simonb "mouse",
81 1.1 simonb "reserved",
82 1.1 simonb "ide primary",
83 1.1 simonb "ide secondary", /* and compact flash connector */
84 1.1 simonb };
85 1.1 simonb
86 1.1 simonb struct pcib_intrhead {
87 1.1 simonb LIST_HEAD(, evbmips_intrhand) intr_q;
88 1.1 simonb struct evcnt intr_count;
89 1.1 simonb int intr_type;
90 1.1 simonb };
91 1.1 simonb
92 1.1 simonb struct pcib_softc {
93 1.12.84.1 matt device_t sc_dev;
94 1.1 simonb
95 1.12.84.1 matt bus_space_tag_t sc_memt;
96 1.1 simonb bus_space_tag_t sc_iot;
97 1.1 simonb bus_space_handle_t sc_ioh_icu1;
98 1.1 simonb bus_space_handle_t sc_ioh_icu2;
99 1.1 simonb bus_space_handle_t sc_ioh_elcr;
100 1.1 simonb
101 1.12.84.1 matt bus_dma_tag_t sc_dmat;
102 1.12.84.1 matt
103 1.2 simonb struct mips_isa_chipset sc_ic;
104 1.1 simonb
105 1.1 simonb struct pcib_intrhead sc_intrtab[ICU_LEN];
106 1.1 simonb
107 1.1 simonb u_int16_t sc_imask;
108 1.1 simonb u_int16_t sc_elcr;
109 1.1 simonb
110 1.1 simonb u_int16_t sc_reserved;
111 1.1 simonb
112 1.1 simonb void *sc_ih;
113 1.1 simonb };
114 1.1 simonb
115 1.1 simonb /*
116 1.1 simonb * XXX
117 1.1 simonb * There is only one pci-isa bridge, and all external interrupts
118 1.1 simonb * are routed through it, so we need to remember the softc when
119 1.1 simonb * called from other interrupt handling code.
120 1.1 simonb */
121 1.1 simonb static struct pcib_softc *my_sc;
122 1.2 simonb struct mips_isa_chipset *pcib_ic;
123 1.1 simonb
124 1.1 simonb static int pcib_match(struct device *, struct cfdata *, void *);
125 1.1 simonb static void pcib_attach(struct device *, struct device *, void *);
126 1.1 simonb static int pcib_intr(void *v);
127 1.1 simonb static void pcib_bridge_callback(struct device *);
128 1.1 simonb static void pcib_set_icus(struct pcib_softc *sc);
129 1.1 simonb static void pcib_cleanup(void *arg);
130 1.1 simonb
131 1.1 simonb static const struct evcnt *
132 1.1 simonb pcib_isa_intr_evcnt(void *, int);
133 1.1 simonb static void *pcib_isa_intr_establish(void *, int, int, int,
134 1.1 simonb int (*)(void *), void *);
135 1.1 simonb static void pcib_isa_intr_disestablish(void *, void *);
136 1.1 simonb static void pcib_isa_attach_hook(struct device *, struct device *,
137 1.1 simonb struct isabus_attach_args *);
138 1.1 simonb static int pcib_isa_intr_alloc(void *, int, int, int *);
139 1.1 simonb static const char *
140 1.1 simonb pcib_isa_intr_string(void *, int);
141 1.1 simonb
142 1.12.84.1 matt CFATTACH_DECL_NEW(pcib, sizeof(struct pcib_softc),
143 1.6 thorpej pcib_match, pcib_attach, NULL, NULL);
144 1.1 simonb
145 1.1 simonb static int
146 1.12.84.1 matt malta_isa_dma_may_bounce(bus_dma_tag_t t, bus_dmamap_t map, int flags,
147 1.12.84.1 matt int *cookieflagsp)
148 1.12.84.1 matt {
149 1.12.84.1 matt if (((map->_dm_size / PAGE_SIZE) + 1) > map->_dm_segcnt)
150 1.12.84.1 matt *cookieflagsp |= _BUS_DMA_MIGHT_NEED_BOUNCE;
151 1.12.84.1 matt
152 1.12.84.1 matt return 0;
153 1.12.84.1 matt }
154 1.12.84.1 matt
155 1.12.84.1 matt static int
156 1.1 simonb pcib_match(struct device *parent, struct cfdata *match, void *aux)
157 1.1 simonb {
158 1.1 simonb struct pci_attach_args *pa = aux;
159 1.1 simonb
160 1.1 simonb if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
161 1.1 simonb PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
162 1.1 simonb return (1);
163 1.1 simonb
164 1.1 simonb return (0);
165 1.1 simonb }
166 1.1 simonb
167 1.1 simonb static void
168 1.1 simonb pcib_attach(struct device *parent, struct device *self, void *aux)
169 1.1 simonb {
170 1.12.84.1 matt struct pci_attach_args * const pa = aux;
171 1.12.84.1 matt struct pcib_softc * const sc = device_private(self);
172 1.12.84.1 matt const char * const xname = device_xname(self);
173 1.1 simonb char devinfo[256];
174 1.12.84.1 matt int error;
175 1.1 simonb
176 1.1 simonb printf("\n");
177 1.1 simonb
178 1.1 simonb if (my_sc != NULL)
179 1.3 provos panic("pcib_attach: already attached!");
180 1.12.84.1 matt my_sc = sc;
181 1.12.84.1 matt sc->sc_dev = self;
182 1.1 simonb
183 1.1 simonb /*
184 1.1 simonb * Just print out a description and defer configuration
185 1.1 simonb * until all PCI devices have been attached.
186 1.1 simonb */
187 1.9 kleink pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
188 1.12.84.1 matt printf("%s: %s, (rev . 0x%02x)\n", xname, devinfo,
189 1.1 simonb PCI_REVISION(pa->pa_class));
190 1.1 simonb
191 1.12.84.1 matt sc->sc_memt = pa->pa_memt;
192 1.12.84.1 matt sc->sc_iot = pa->pa_iot;
193 1.12.84.1 matt
194 1.12.84.1 matt /*
195 1.12.84.1 matt * Initialize the DMA tag used for ISA DMA.
196 1.12.84.1 matt */
197 1.12.84.1 matt error = bus_dmatag_subregion(pa->pa_dmat, MALTA_DMA_ISA_PHYSBASE,
198 1.12.84.1 matt MALTA_DMA_ISA_PHYSBASE + MALTA_DMA_ISA_SIZE, &sc->sc_dmat, 0);
199 1.12.84.1 matt if (error)
200 1.12.84.1 matt panic("malta_dma_init: failed to create ISA dma tag: %d",
201 1.12.84.1 matt error);
202 1.12.84.1 matt sc->sc_dmat->_may_bounce = malta_isa_dma_may_bounce;
203 1.1 simonb
204 1.1 simonb /*
205 1.1 simonb * Map the PIC/ELCR registers.
206 1.1 simonb */
207 1.12.84.1 matt if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
208 1.12.84.1 matt printf("%s: unable to map ELCR registers\n", xname);
209 1.12.84.1 matt if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
210 1.12.84.1 matt printf("%s: unable to map ICU1 registers\n", xname);
211 1.12.84.1 matt if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
212 1.12.84.1 matt printf("%s: unable to map ICU2 registers\n", xname);
213 1.1 simonb
214 1.1 simonb /* All interrupts default to "masked off". */
215 1.12.84.1 matt sc->sc_imask = 0xffff;
216 1.1 simonb
217 1.1 simonb /* All interrupts default to edge-triggered. */
218 1.12.84.1 matt sc->sc_elcr = 0;
219 1.1 simonb
220 1.1 simonb /*
221 1.1 simonb * Initialize the 8259s.
222 1.1 simonb */
223 1.1 simonb /* reset, program device, 4 bytes */
224 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1,
225 1.1 simonb ICW1_SELECT | ICW1_IC4);
226 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2,
227 1.1 simonb ICW2_VECTOR(0)/*XXX*/);
228 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3,
229 1.1 simonb ICW3_CASCADE(2));
230 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4,
231 1.1 simonb ICW4_8086);
232 1.1 simonb
233 1.1 simonb /* mask all interrupts */
234 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
235 1.12.84.1 matt sc->sc_imask & 0xff);
236 1.1 simonb
237 1.1 simonb /* enable special mask mode */
238 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
239 1.1 simonb OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
240 1.1 simonb
241 1.1 simonb /* read IRR by default */
242 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
243 1.1 simonb OCW3_SELECT | OCW3_RR);
244 1.1 simonb
245 1.1 simonb /* reset, program device, 4 bytes */
246 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1,
247 1.1 simonb ICW1_SELECT | ICW1_IC4);
248 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2,
249 1.1 simonb ICW2_VECTOR(0)/*XXX*/);
250 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3,
251 1.1 simonb ICW3_CASCADE(2));
252 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4,
253 1.1 simonb ICW4_8086);
254 1.1 simonb
255 1.1 simonb /* mask all interrupts */
256 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
257 1.12.84.1 matt sc->sc_imask & 0xff);
258 1.1 simonb
259 1.1 simonb /* enable special mask mode */
260 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
261 1.1 simonb OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
262 1.1 simonb
263 1.1 simonb /* read IRR by default */
264 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
265 1.1 simonb OCW3_SELECT | OCW3_RR);
266 1.1 simonb
267 1.1 simonb /*
268 1.1 simonb * Default all interrupts to edge-triggered.
269 1.1 simonb */
270 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
271 1.12.84.1 matt sc->sc_elcr & 0xff);
272 1.12.84.1 matt bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
273 1.12.84.1 matt (sc->sc_elcr >> 8) & 0xff);
274 1.1 simonb
275 1.1 simonb /*
276 1.1 simonb * Some ISA interrupts are reserved for devices that
277 1.1 simonb * we know are hard-wired to certain IRQs.
278 1.1 simonb */
279 1.12.84.1 matt sc->sc_reserved =
280 1.1 simonb (1U << 0) | /* timer */
281 1.1 simonb (1U << 1) | /* keyboard controller (keyboard) */
282 1.1 simonb (1U << 2) | /* PIC cascade */
283 1.1 simonb (1U << 3) | /* COM 2 */
284 1.1 simonb (1U << 4) | /* COM 1 */
285 1.1 simonb (1U << 6) | /* floppy */
286 1.1 simonb (1U << 7) | /* centronics */
287 1.1 simonb (1U << 8) | /* RTC */
288 1.1 simonb (1U << 9) | /* I2C */
289 1.1 simonb (1U << 12) | /* keyboard controller (mouse) */
290 1.1 simonb (1U << 14) | /* IDE primary */
291 1.1 simonb (1U << 15); /* IDE secondary */
292 1.1 simonb
293 1.1 simonb /* Set up our ISA chipset. */
294 1.12.84.1 matt sc->sc_ic.ic_v = sc;
295 1.12.84.1 matt sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
296 1.12.84.1 matt sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
297 1.12.84.1 matt sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
298 1.12.84.1 matt sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
299 1.12.84.1 matt sc->sc_ic.ic_intr_string = pcib_isa_intr_string;
300 1.1 simonb
301 1.12.84.1 matt pcib_ic = &sc->sc_ic; /* XXX for external use */
302 1.1 simonb
303 1.1 simonb /* Initialize our interrupt table. */
304 1.12.84.1 matt for (size_t i = 0; i < ICU_LEN; i++) {
305 1.1 simonb #if 0
306 1.1 simonb char irqstr[8]; /* 4 + 2 + NULL + sanity */
307 1.1 simonb
308 1.1 simonb sprintf(irqstr, "irq %d", i);
309 1.12.84.1 matt evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
310 1.1 simonb EVCNT_TYPE_INTR, NULL, "pcib", irqstr);
311 1.1 simonb #else
312 1.12.84.1 matt evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
313 1.1 simonb EVCNT_TYPE_INTR, NULL, "pcib", isa_intrnames[i]);
314 1.1 simonb #endif
315 1.12.84.1 matt LIST_INIT(&sc->sc_intrtab[i].intr_q);
316 1.12.84.1 matt sc->sc_intrtab[i].intr_type = IST_NONE;
317 1.1 simonb }
318 1.1 simonb
319 1.1 simonb /* Hook up our interrupt handler. */
320 1.12.84.1 matt sc->sc_ih = evbmips_intr_establish(MALTA_SOUTHBRIDGE_INTR, pcib_intr, sc);
321 1.12.84.1 matt if (sc->sc_ih == NULL)
322 1.1 simonb printf("%s: WARNING: unable to register interrupt handler\n",
323 1.12.84.1 matt xname);
324 1.1 simonb
325 1.1 simonb
326 1.1 simonb /*
327 1.1 simonb * Disable ISA interrupts before returning to YAMON.
328 1.1 simonb */
329 1.12.84.1 matt if (shutdownhook_establish(pcib_cleanup, sc) == NULL)
330 1.1 simonb panic("pcib_attach: could not establish shutdown hook");
331 1.1 simonb
332 1.1 simonb config_defer(self, pcib_bridge_callback);
333 1.1 simonb }
334 1.1 simonb
335 1.1 simonb static void
336 1.12.84.1 matt pcib_bridge_callback(device_t self)
337 1.1 simonb {
338 1.12.84.1 matt struct pcib_softc *sc = device_private(self);
339 1.1 simonb struct isabus_attach_args iba;
340 1.1 simonb
341 1.1 simonb /*
342 1.1 simonb * Attach the ISA bus behind this bridge.
343 1.1 simonb */
344 1.1 simonb memset(&iba, 0, sizeof(iba));
345 1.1 simonb
346 1.12.84.1 matt iba.iba_iot = sc->sc_iot;
347 1.12.84.1 matt iba.iba_memt = sc->sc_memt;
348 1.12.84.1 matt iba.iba_dmat = sc->sc_dmat;
349 1.1 simonb
350 1.1 simonb iba.iba_ic = &sc->sc_ic;
351 1.1 simonb iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
352 1.1 simonb
353 1.12.84.1 matt config_found_ia(sc->sc_dev, "isabus", &iba, isabusprint);
354 1.1 simonb }
355 1.1 simonb
356 1.1 simonb static void
357 1.1 simonb pcib_isa_attach_hook(struct device *parent, struct device *self,
358 1.1 simonb struct isabus_attach_args *iba)
359 1.1 simonb {
360 1.1 simonb
361 1.1 simonb /* Nothing to do. */
362 1.1 simonb }
363 1.1 simonb
364 1.1 simonb static void
365 1.1 simonb pcib_set_icus(struct pcib_softc *sc)
366 1.1 simonb {
367 1.1 simonb
368 1.1 simonb /* Enable the cascade IRQ (2) if 8-15 is enabled. */
369 1.1 simonb if ((sc->sc_imask & 0xff00) != 0xff00)
370 1.1 simonb sc->sc_imask &= ~(1U << 2);
371 1.1 simonb else
372 1.1 simonb sc->sc_imask |= (1U << 2);
373 1.1 simonb
374 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
375 1.1 simonb sc->sc_imask & 0xff);
376 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
377 1.1 simonb (sc->sc_imask >> 8) & 0xff);
378 1.1 simonb
379 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
380 1.1 simonb sc->sc_elcr & 0xff);
381 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
382 1.1 simonb (sc->sc_elcr >> 8) & 0xff);
383 1.1 simonb }
384 1.1 simonb
385 1.1 simonb static int
386 1.1 simonb pcib_intr(void *v)
387 1.1 simonb {
388 1.1 simonb struct pcib_softc *sc = v;
389 1.1 simonb struct evbmips_intrhand *ih;
390 1.1 simonb int irq;
391 1.1 simonb
392 1.1 simonb for (;;) {
393 1.1 simonb #if 1
394 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
395 1.1 simonb OCW3_SELECT | OCW3_POLL);
396 1.1 simonb irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
397 1.1 simonb if ((irq & OCW3_POLL_PENDING) == 0)
398 1.1 simonb return (1);
399 1.1 simonb
400 1.1 simonb irq = OCW3_POLL_IRQ(irq);
401 1.1 simonb
402 1.1 simonb if (irq == 2) {
403 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
404 1.1 simonb PIC_OCW3, OCW3_SELECT | OCW3_POLL);
405 1.1 simonb irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
406 1.1 simonb PIC_OCW3);
407 1.1 simonb if (irq & OCW3_POLL_PENDING)
408 1.1 simonb irq = OCW3_POLL_IRQ(irq) + 8;
409 1.1 simonb else
410 1.1 simonb irq = 2;
411 1.1 simonb }
412 1.1 simonb #else
413 1.1 simonb /* XXX - should be a function call to gt.c? */
414 1.1 simonb irq = GT_REGVAL(GT_PCI0_INTR_ACK) & 0xff;
415 1.1 simonb
416 1.1 simonb /*
417 1.1 simonb * From YAMON source code:
418 1.1 simonb *
419 1.1 simonb * IRQ7 is used to detect spurious interrupts.
420 1.1 simonb * The interrupt acknowledge cycle returns IRQ7, if no
421 1.1 simonb * interrupts is requested.
422 1.1 simonb * We can differentiate between this situation and a
423 1.1 simonb * "Normal" IRQ7 by reading the ISR.
424 1.1 simonb */
425 1.1 simonb
426 1.1 simonb if (irq == 7) {
427 1.1 simonb int reg;
428 1.1 simonb
429 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
430 1.1 simonb OCW3_SELECT | OCW3_RR | OCW3_RIS);
431 1.1 simonb reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1,
432 1.1 simonb PIC_OCW3);
433 1.1 simonb if (!(reg & (1 << 7)))
434 1.1 simonb break; /* spurious interrupt */
435 1.1 simonb }
436 1.1 simonb #endif
437 1.1 simonb
438 1.1 simonb sc->sc_intrtab[irq].intr_count.ev_count++;
439 1.1 simonb LIST_FOREACH(ih, &sc->sc_intrtab[irq].intr_q, ih_q)
440 1.1 simonb (*ih->ih_func)(ih->ih_arg);
441 1.1 simonb
442 1.1 simonb /* Send a specific EOI to the 8259. */
443 1.1 simonb if (irq > 7) {
444 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
445 1.12 tsutsui PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
446 1.1 simonb OCW2_ILS(irq & 7));
447 1.1 simonb irq = 2;
448 1.1 simonb }
449 1.1 simonb
450 1.1 simonb bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
451 1.12 tsutsui OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
452 1.1 simonb }
453 1.1 simonb }
454 1.1 simonb
455 1.1 simonb const char *
456 1.1 simonb pcib_isa_intr_string(void *v, int irq)
457 1.1 simonb {
458 1.1 simonb static char irqstr[12]; /* 8 + 2 + NULL + sanity */
459 1.1 simonb
460 1.1 simonb if (irq == 0 || irq >= ICU_LEN || irq == 2)
461 1.3 provos panic("pcib_isa_intr_string: bogus isa irq 0x%x", irq);
462 1.1 simonb
463 1.1 simonb sprintf(irqstr, "isa irq %d", irq);
464 1.1 simonb return (irqstr);
465 1.1 simonb }
466 1.1 simonb
467 1.1 simonb const struct evcnt *
468 1.1 simonb pcib_isa_intr_evcnt(void *v, int irq)
469 1.1 simonb {
470 1.1 simonb
471 1.1 simonb if (irq == 0 || irq >= ICU_LEN || irq == 2)
472 1.3 provos panic("pcib_isa_intr_evcnt: bogus isa irq 0x%x", irq);
473 1.1 simonb
474 1.1 simonb return (&my_sc->sc_intrtab[irq].intr_count);
475 1.1 simonb }
476 1.1 simonb
477 1.1 simonb void *
478 1.1 simonb pcib_isa_intr_establish(void *v, int irq, int type, int level,
479 1.1 simonb int (*func)(void *), void *arg)
480 1.1 simonb {
481 1.1 simonb struct evbmips_intrhand *ih;
482 1.1 simonb int s;
483 1.1 simonb
484 1.1 simonb if (irq >= ICU_LEN || irq == 2 || type == IST_NONE)
485 1.1 simonb panic("pcib_isa_intr_establish: bad irq or type");
486 1.1 simonb
487 1.1 simonb switch (my_sc->sc_intrtab[irq].intr_type) {
488 1.1 simonb case IST_NONE:
489 1.1 simonb my_sc->sc_intrtab[irq].intr_type = type;
490 1.1 simonb break;
491 1.1 simonb
492 1.1 simonb case IST_EDGE:
493 1.1 simonb case IST_LEVEL:
494 1.1 simonb if (type == my_sc->sc_intrtab[irq].intr_type)
495 1.1 simonb break;
496 1.1 simonb /* FALLTHROUGH */
497 1.1 simonb case IST_PULSE:
498 1.1 simonb /*
499 1.1 simonb * We can't share interrupts in this case.
500 1.1 simonb */
501 1.1 simonb return (NULL);
502 1.1 simonb }
503 1.1 simonb
504 1.1 simonb ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
505 1.1 simonb if (ih == NULL)
506 1.1 simonb return (NULL);
507 1.1 simonb
508 1.1 simonb ih->ih_func = func;
509 1.1 simonb ih->ih_arg = arg;
510 1.1 simonb ih->ih_irq = irq;
511 1.1 simonb
512 1.1 simonb s = splhigh();
513 1.1 simonb
514 1.1 simonb /* Insert the handler into the table. */
515 1.1 simonb LIST_INSERT_HEAD(&my_sc->sc_intrtab[irq].intr_q, ih, ih_q);
516 1.1 simonb my_sc->sc_intrtab[irq].intr_type = type;
517 1.1 simonb
518 1.1 simonb /* Enable it, set trigger mode. */
519 1.1 simonb my_sc->sc_imask &= ~(1 << irq);
520 1.1 simonb if (my_sc->sc_intrtab[irq].intr_type == IST_LEVEL)
521 1.1 simonb my_sc->sc_elcr |= (1 << irq);
522 1.1 simonb else
523 1.1 simonb my_sc->sc_elcr &= ~(1 << irq);
524 1.1 simonb
525 1.1 simonb pcib_set_icus(my_sc);
526 1.1 simonb
527 1.1 simonb splx(s);
528 1.1 simonb
529 1.1 simonb return (ih);
530 1.1 simonb }
531 1.1 simonb
532 1.1 simonb void
533 1.1 simonb pcib_isa_intr_disestablish(void *v, void *arg)
534 1.1 simonb {
535 1.1 simonb struct evbmips_intrhand *ih = arg;
536 1.1 simonb int s;
537 1.1 simonb
538 1.1 simonb s = splhigh();
539 1.1 simonb
540 1.1 simonb LIST_REMOVE(ih, ih_q);
541 1.1 simonb
542 1.1 simonb /* If there are no more handlers on this IRQ, disable it. */
543 1.1 simonb if (LIST_FIRST(&my_sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
544 1.1 simonb my_sc->sc_imask |= (1 << ih->ih_irq);
545 1.1 simonb pcib_set_icus(my_sc);
546 1.1 simonb }
547 1.1 simonb
548 1.1 simonb splx(s);
549 1.1 simonb
550 1.1 simonb free(ih, M_DEVBUF);
551 1.1 simonb }
552 1.1 simonb
553 1.1 simonb static int
554 1.1 simonb pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
555 1.1 simonb {
556 1.1 simonb int i, tmp, bestirq, count;
557 1.1 simonb struct evbmips_intrhand *ih;
558 1.1 simonb
559 1.1 simonb if (type == IST_NONE)
560 1.1 simonb panic("pcib_intr_alloc: bogus type");
561 1.1 simonb
562 1.1 simonb bestirq = -1;
563 1.1 simonb count = -1;
564 1.1 simonb
565 1.1 simonb mask &= ~my_sc->sc_reserved;
566 1.1 simonb
567 1.1 simonb for (i = 0; i < ICU_LEN; i++) {
568 1.1 simonb if ((mask & (1 << i)) == 0)
569 1.1 simonb continue;
570 1.1 simonb
571 1.1 simonb switch (my_sc->sc_intrtab[i].intr_type) {
572 1.1 simonb case IST_NONE:
573 1.1 simonb /*
574 1.1 simonb * If nothing's using the IRQ, just return it.
575 1.1 simonb */
576 1.1 simonb *irq = i;
577 1.1 simonb return (0);
578 1.1 simonb
579 1.1 simonb case IST_EDGE:
580 1.1 simonb case IST_LEVEL:
581 1.1 simonb if (type != my_sc->sc_intrtab[i].intr_type)
582 1.1 simonb continue;
583 1.1 simonb /*
584 1.1 simonb * If the IRQ is sharable, count the number of
585 1.1 simonb * other handlers, and if it's smaller than the
586 1.1 simonb * last IRQ like this, remember it.
587 1.1 simonb */
588 1.1 simonb tmp = 0;
589 1.1 simonb for (ih = LIST_FIRST(&my_sc->sc_intrtab[i].intr_q);
590 1.1 simonb ih != NULL; ih = LIST_NEXT(ih, ih_q))
591 1.1 simonb tmp++;
592 1.1 simonb if (bestirq == -1 || count > tmp) {
593 1.1 simonb bestirq = i;
594 1.1 simonb count = tmp;
595 1.1 simonb }
596 1.1 simonb break;
597 1.1 simonb
598 1.1 simonb case IST_PULSE:
599 1.1 simonb /* This just isn't sharable. */
600 1.1 simonb continue;
601 1.1 simonb }
602 1.1 simonb }
603 1.1 simonb
604 1.1 simonb if (bestirq == -1)
605 1.1 simonb return (1);
606 1.1 simonb
607 1.1 simonb *irq = bestirq;
608 1.1 simonb return (0);
609 1.1 simonb }
610 1.1 simonb
611 1.1 simonb static void
612 1.1 simonb pcib_cleanup(void *arg)
613 1.1 simonb {
614 1.1 simonb
615 1.1 simonb my_sc->sc_imask = 0xffff;
616 1.1 simonb pcib_set_icus(my_sc);
617 1.1 simonb }
618