pcib.c revision 1.3 1 /* $NetBSD: pcib.c,v 1.3 2001/06/10 09:13:07 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
40
41 __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.3 2001/06/10 09:13:07 thorpej Exp $");
42
43 #include "opt_algor_p5064.h"
44 #include "opt_algor_p6032.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/device.h>
50 #include <sys/malloc.h>
51
52 #include <machine/intr.h>
53 #include <machine/bus.h>
54
55 #include <dev/isa/isareg.h>
56 #include <dev/isa/isavar.h>
57
58 #include <dev/pci/pcireg.h>
59 #include <dev/pci/pcivar.h>
60 #include <dev/pci/pcidevs.h>
61
62 #ifdef ALGOR_P5064
63 #include <algor/algor/algor_p5064var.h>
64 #endif
65
66 #ifdef ALGOR_P6032
67 #include <algor/algor/algor_p6032var.h>
68 #endif
69
70 const char *pcib_intrnames[16] = {
71 "irq 0",
72 "irq 1",
73 "irq 2",
74 "irq 3",
75 "irq 4",
76 "irq 5",
77 "irq 6",
78 "irq 7",
79 "irq 8",
80 "irq 9",
81 "irq 10",
82 "irq 11",
83 "irq 12",
84 "irq 13",
85 "irq 14",
86 "irq 15",
87 };
88
89 struct pcib_intrhead {
90 LIST_HEAD(, algor_intrhand) intr_q;
91 struct evcnt intr_count;
92 int intr_type;
93 };
94
95 struct pcib_softc {
96 struct device sc_dev;
97
98 bus_space_tag_t sc_iot;
99 bus_space_handle_t sc_ioh_icu1;
100 bus_space_handle_t sc_ioh_icu2;
101 bus_space_handle_t sc_ioh_elcr;
102
103 struct algor_isa_chipset sc_ic;
104
105 struct pcib_intrhead sc_intrtab[16];
106
107 u_int16_t sc_inten;
108 u_int16_t sc_elcr;
109
110 #if defined(ALGOR_P5064)
111 isa_chipset_tag_t sc_parent_ic;
112 u_int16_t sc_reserved;
113 #endif
114
115 void *sc_ih;
116 };
117
118 int pcib_match(struct device *, struct cfdata *, void *);
119 void pcib_attach(struct device *, struct device *, void *);
120
121 struct cfattach pcib_ca = {
122 sizeof(struct pcib_softc), pcib_match, pcib_attach,
123 };
124
125 int pcib_print(void *, const char *pnp);
126 void pcib_isa_attach_hook(struct device *, struct device *,
127 struct isabus_attach_args *);
128
129 int pcib_intr(void *);
130
131 void pcib_bridge_callback(struct device *);
132
133 const struct evcnt *pcib_isa_intr_evcnt(void *, int);
134 void *pcib_isa_intr_establish(void *, int, int, int,
135 int (*)(void *), void *);
136 void pcib_isa_intr_disestablish(void *, void *);
137 int pcib_isa_intr_alloc(void *, int, int, int *);
138
139 void pcib_set_icus(struct pcib_softc *);
140
141 int
142 pcib_match(struct device *parent, struct cfdata *match, void *aux)
143 {
144 struct pci_attach_args *pa = aux;
145
146 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
147 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
148 return (1);
149
150 return (0);
151 }
152
153 void
154 pcib_attach(struct device *parent, struct device *self, void *aux)
155 {
156 struct pcib_softc *sc = (void *) self;
157 struct pci_attach_args *pa = aux;
158 char devinfo[256];
159 int i;
160
161 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
162 printf(": %s (rev. 0x%02x)\n", devinfo,
163 PCI_REVISION(pa->pa_class));
164
165 sc->sc_iot = pa->pa_iot;
166
167 /*
168 * Map the PIC/ELCR registers.
169 */
170 if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
171 printf("%s: unable to map ELCR registers\n",
172 sc->sc_dev.dv_xname);
173 if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
174 printf("%s: unable to map ICU1 registers\n",
175 sc->sc_dev.dv_xname);
176 if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
177 printf("%s: unable to map ICU2 registers\n",
178 sc->sc_dev.dv_xname);
179
180 /*
181 * Initialize the 8259s.
182 */
183
184 /* ICW1: reset; program device, 4 bytes */
185 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x11);
186
187 /* ICW2: vector base address */
188 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 32/*XXX*/);
189
190 /* ICW3: cascade mode */
191 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 0x04);
192
193 /* ICW4: 8086 mode */
194 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1, 0x01);
195
196 /* OCW1: mask all interrupts */
197 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1,
198 ~sc->sc_inten & 0xff);
199
200 /* OCW3: enable special mask mode */
201 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x68);
202
203 /* OCW3: read IRR by default */
204 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0, 0x0a);
205
206
207 /* ICW1: reset; program device, 4 bytes */
208 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x11);
209
210 /* ICW2: vector base address */
211 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 32+8/*XXX*/);
212
213 /* ICW3: slave ID code */
214 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 0x02);
215
216 /* ICW4: 8086 mode */
217 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1, 0x01);
218
219 /* OCW1: mask all interrupts */
220 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1,
221 (~sc->sc_inten >> 8) & 0xff);
222
223 /* OCW3: enable special mask mode */
224 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x68);
225
226 /* OCW3: read IRR by default */
227 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 0, 0x0a);
228
229 /*
230 * Default all interrupts to edge-triggered.
231 */
232 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
233 sc->sc_elcr & 0xff);
234 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
235 (sc->sc_elcr >> 8) & 0xff);
236
237 #if defined(ALGOR_P5064)
238 /*
239 * Some "ISA" interrupts are a little wacky, wired up directly
240 * to the P-5064 interrupt controller.
241 */
242 sc->sc_reserved =
243 (1 << 1) |
244 (1 << 3) |
245 (1 << 4) |
246 (1 << 6) |
247 (1 << 7) |
248 (1 << 8) |
249 (1 << 12) |
250 (1 << 14) |
251 (1 << 15);
252
253 sc->sc_parent_ic = &p5064_configuration.ac_ic;
254 #endif /* ALGOR_P5064 */
255
256 /* Set up our ISA chipset. */
257 sc->sc_ic.ic_v = sc;
258 sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
259 sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
260 sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
261 sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
262
263 /* Initialize our interrupt table. */
264 for (i = 0; i < 16; i++) {
265 LIST_INIT(&sc->sc_intrtab[i].intr_q);
266 evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
267 EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
268 sc->sc_intrtab[i].intr_type = IST_NONE;
269 }
270
271 /* Hook up our interrupt handler. */
272 #if defined(ALGOR_P5064)
273 sc->sc_ih = algor_p5064_intr_establish(&p5064_irqmap[
274 P5064_IRQ_ISABRIDGE], pcib_intr, sc);
275 #elif defined(ALGOR_P6032)
276 sc->sc_ih = algor_p6032_intr_establish(&p6032_irqmap[XXX],
277 pcib_intr, sc);
278 #endif
279 if (sc->sc_ih == NULL)
280 printf("%s: WARNING: unable to register interrupt handler\n",
281 sc->sc_dev.dv_xname);
282
283 config_defer(self, pcib_bridge_callback);
284 }
285
286 void
287 pcib_bridge_callback(self)
288 struct device *self;
289 {
290 struct pcib_softc *sc = (struct pcib_softc *)self;
291 struct isabus_attach_args iba;
292
293 memset(&iba, 0, sizeof(iba));
294
295 iba.iba_busname = "isa";
296 #if defined(ALGOR_P5064)
297 {
298 struct p5064_config *acp = &p5064_configuration;
299
300 iba.iba_iot = &acp->ac_iot;
301 iba.iba_memt = &acp->ac_memt;
302 iba.iba_dmat = &acp->ac_isa_dmat;
303 iba.iba_ic = &acp->ac_ic;
304 }
305 #elif defined(ALGOR_P6032)
306 {
307 /* XXX */
308 }
309 #endif
310
311 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
312
313 (void) config_found(&sc->sc_dev, &iba, pcib_print);
314 }
315
316 int
317 pcib_print(void *aux, const char *pnp)
318 {
319 struct isabus_attach_args *iba;
320
321 if (pnp)
322 printf("%s at %s", iba->iba_busname, pnp);
323 return (UNCONF);
324 }
325
326 void
327 pcib_isa_attach_hook(struct device *parent, struct device *self,
328 struct isabus_attach_args *iba)
329 {
330
331 /* Nothing to do. */
332 }
333
334 void
335 pcib_set_icus(struct pcib_softc *sc)
336 {
337
338 /* Enable the cascade IRQ (2) if 8-15 is enabled. */
339 if (sc->sc_inten & 0xff00)
340 sc->sc_inten |= (1 << 2);
341 else
342 sc->sc_inten &= ~(1 << 2);
343
344 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 1,
345 ~sc->sc_inten & 0xff);
346 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 1,
347 (~sc->sc_inten >> 8) & 0xff);
348
349 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
350 sc->sc_elcr & 0xff);
351 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
352 (sc->sc_elcr >> 8) & 0xff);
353 }
354
355 int
356 pcib_intr(void *v)
357 {
358 struct pcib_softc *sc = v;
359 struct algor_intrhand *ih;
360 u_int16_t ipending;
361 int i;
362
363 ipending = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, 0) |
364 (bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 0) << 8);
365 ipending &= (sc->sc_inten & ~0x02);
366 if (ipending == 0)
367 return (0);
368
369 for (i = 0; i < 16; i++) {
370 if ((ipending & (1 << i)) == 0)
371 continue;
372 sc->sc_intrtab[i].intr_count.ev_count++;
373 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
374 ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
375 (*ih->ih_func)(ih->ih_arg);
376 }
377
378 /* Send a specific EOI to the 8259. */
379 if (i > 7)
380 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
381 0, 0x20 | (i & 0x07));
382 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, 0,
383 0x20 | (i > 7 ? 2 : i));
384 }
385
386 return (1);
387 }
388
389 const struct evcnt *
390 pcib_isa_intr_evcnt(void *v, int irq)
391 {
392 struct pcib_softc *sc = v;
393
394 return (&sc->sc_intrtab[irq].intr_count);
395 }
396
397 void *
398 pcib_isa_intr_establish(void *v, int irq, int type, int level,
399 int (*func)(void *), void *arg)
400 {
401 struct pcib_softc *sc = v;
402 struct algor_intrhand *ih;
403 int s;
404
405 if (irq > 15 || irq == 2 || type == IST_NONE)
406 panic("pcib_isa_intr_establish: bad irq or type");
407
408 #if defined(ALGOR_P5064)
409 if (sc->sc_reserved & (1 << irq)) {
410 ih = isa_intr_establish(sc->sc_parent_ic, irq, type,
411 level, func, arg);
412 if (ih != NULL)
413 ih->ih_irq = irq;
414 }
415 #endif
416
417 switch (sc->sc_intrtab[irq].intr_type) {
418 case IST_NONE:
419 sc->sc_intrtab[irq].intr_type = type;
420 break;
421
422 case IST_EDGE:
423 case IST_LEVEL:
424 if (type == sc->sc_intrtab[irq].intr_type)
425 break;
426 /* FALLTHROUGH */
427 case IST_PULSE:
428 /*
429 * We can't share interrupts in this case.
430 */
431 return (NULL);
432 }
433
434 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
435 if (ih == NULL)
436 return (NULL);
437
438 ih->ih_func = func;
439 ih->ih_arg = arg;
440 ih->ih_irq = irq;
441 ih->ih_irqmap = NULL;
442
443 s = splhigh();
444
445 /* Insert the handler into the table. */
446 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
447 sc->sc_intrtab[irq].intr_type = type;
448
449 /* Enable it, set trigger mode. */
450 sc->sc_inten |= (1 << irq);
451 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
452 sc->sc_elcr |= (1 << irq);
453 else
454 sc->sc_elcr &= ~(1 << irq);
455
456 pcib_set_icus(sc);
457
458 splx(s);
459
460 return (ih);
461 }
462
463 void
464 pcib_isa_intr_disestablish(void *v, void *arg)
465 {
466 struct pcib_softc *sc = v;
467 struct algor_intrhand *ih = arg;
468 int s;
469
470 #if defined(ALGOR_P5064)
471 if (sc->sc_reserved & (1 << ih->ih_irq)) {
472 isa_intr_disestablish(sc->sc_parent_ic, ih);
473 return;
474 }
475 #endif
476
477 s = splhigh();
478
479 LIST_REMOVE(ih, ih_q);
480
481 /* If there are no more handlers on this IRQ, disable it. */
482 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
483 sc->sc_inten &= ~(1 << ih->ih_irq);
484 pcib_set_icus(sc);
485 }
486
487 splx(s);
488
489 free(ih, M_DEVBUF);
490 }
491
492 int
493 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
494 {
495 struct pcib_softc *sc = v;
496 int i, tmp, bestirq, count;
497 struct algor_intrhand *ih;
498
499 if (type == IST_NONE)
500 panic("pcib_intr_alloc: bogus type");
501
502 bestirq = -1;
503 count = -1;
504
505 #if defined(ALGOR_P5064)
506 mask &= ~sc->sc_reserved;
507 #endif
508
509 for (i = 0; i < 16; i++) {
510 if (i == 2 || (mask & (1 << i)) == 0)
511 continue;
512
513 switch (sc->sc_intrtab[i].intr_type) {
514 case IST_NONE:
515 /*
516 * If nothing's using the IRQ, just return it.
517 */
518 *irq = i;
519 return (0);
520
521 case IST_EDGE:
522 case IST_LEVEL:
523 if (type != sc->sc_intrtab[i].intr_type)
524 continue;
525 /*
526 * If the IRQ is sharable, count the number of
527 * other handlers, and if it's smaller than the
528 * last IRQ like this, remember it.
529 */
530 tmp = 0;
531 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
532 ih != NULL; ih = LIST_NEXT(ih, ih_q))
533 tmp++;
534 if (bestirq == -1 || count > tmp) {
535 bestirq = i;
536 count = tmp;
537 }
538 break;
539
540 case IST_PULSE:
541 /* This just isn't sharable. */
542 continue;
543 }
544 }
545
546 if (bestirq == -1)
547 return (1);
548
549 *irq = bestirq;
550 return (0);
551 }
552