pcib.c revision 1.6 1 /* $NetBSD: pcib.c,v 1.6 2001/06/21 05:20:54 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.6 2001/06/21 05:20:54 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 #include <dev/ic/i8259reg.h>
63
64 #ifdef ALGOR_P5064
65 #include <algor/algor/algor_p5064var.h>
66 #endif
67
68 #ifdef ALGOR_P6032
69 #include <algor/algor/algor_p6032var.h>
70 #endif
71
72 const char *pcib_intrnames[16] = {
73 "irq 0",
74 "irq 1",
75 "irq 2",
76 "irq 3",
77 "irq 4",
78 "irq 5",
79 "irq 6",
80 "irq 7",
81 "irq 8",
82 "irq 9",
83 "irq 10",
84 "irq 11",
85 "irq 12",
86 "irq 13",
87 "irq 14",
88 "irq 15",
89 };
90
91 struct pcib_intrhead {
92 LIST_HEAD(, algor_intrhand) intr_q;
93 struct evcnt intr_count;
94 int intr_type;
95 };
96
97 struct pcib_softc {
98 struct device sc_dev;
99
100 bus_space_tag_t sc_iot;
101 bus_space_handle_t sc_ioh_icu1;
102 bus_space_handle_t sc_ioh_icu2;
103 bus_space_handle_t sc_ioh_elcr;
104
105 struct algor_isa_chipset sc_ic;
106
107 struct pcib_intrhead sc_intrtab[16];
108
109 u_int16_t sc_imask;
110 u_int16_t sc_elcr;
111
112 #if defined(ALGOR_P5064)
113 isa_chipset_tag_t sc_parent_ic;
114 #endif
115
116 u_int16_t sc_reserved;
117
118 void *sc_ih;
119 };
120
121 int pcib_match(struct device *, struct cfdata *, void *);
122 void pcib_attach(struct device *, struct device *, void *);
123
124 struct cfattach pcib_ca = {
125 sizeof(struct pcib_softc), pcib_match, pcib_attach,
126 };
127
128 int pcib_print(void *, const char *pnp);
129 void pcib_isa_attach_hook(struct device *, struct device *,
130 struct isabus_attach_args *);
131
132 int pcib_intr(void *);
133
134 void pcib_bridge_callback(struct device *);
135
136 const struct evcnt *pcib_isa_intr_evcnt(void *, int);
137 void *pcib_isa_intr_establish(void *, int, int, int,
138 int (*)(void *), void *);
139 void pcib_isa_intr_disestablish(void *, void *);
140 int pcib_isa_intr_alloc(void *, int, int, int *);
141
142 void pcib_set_icus(struct pcib_softc *);
143
144 int
145 pcib_match(struct device *parent, struct cfdata *match, void *aux)
146 {
147 struct pci_attach_args *pa = aux;
148
149 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
150 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
151 return (1);
152
153 return (0);
154 }
155
156 void
157 pcib_attach(struct device *parent, struct device *self, void *aux)
158 {
159 struct pcib_softc *sc = (void *) self;
160 struct pci_attach_args *pa = aux;
161 char devinfo[256];
162 int i;
163
164 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
165 printf(": %s (rev. 0x%02x)\n", devinfo,
166 PCI_REVISION(pa->pa_class));
167
168 sc->sc_iot = pa->pa_iot;
169
170 /*
171 * Map the PIC/ELCR registers.
172 */
173 if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
174 printf("%s: unable to map ELCR registers\n",
175 sc->sc_dev.dv_xname);
176 if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
177 printf("%s: unable to map ICU1 registers\n",
178 sc->sc_dev.dv_xname);
179 if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
180 printf("%s: unable to map ICU2 registers\n",
181 sc->sc_dev.dv_xname);
182
183 /* All interrupts default to "masked off". */
184 sc->sc_imask = 0xffff;
185
186 /* All interrupts default to edge-triggered. */
187 sc->sc_elcr = 0;
188
189 /*
190 * Initialize the 8259s.
191 */
192
193 /* reset, program device, 4 bytes */
194 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1,
195 ICW_SELECT(1) | ICW1_IC4);
196 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2,
197 ICW2_VECTOR(32)/*XXX*/);
198 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3,
199 ICW3_CASCADE);
200 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4,
201 ICW4_8086);
202
203 /* mask all interrupts */
204 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
205 sc->sc_imask & 0xff);
206
207 /* enable special mask mode */
208 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
209 OCW3_SELECT | OCW3_ESMM | OCW3_SMM);
210
211 /* read IRR by default */
212 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
213 OCW3_SELECT | OCW3_RR_CMD(OCW3_RR_CMD_READ_IRQ));
214
215
216 /* reset; program device, 4 bytes */
217 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1,
218 ICW_SELECT(1) | ICW1_IC4);
219 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2,
220 ICW2_VECTOR(32 + 8)/*XXX*/);
221 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3,
222 ICW3_SIC(2));
223 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4,
224 ICW4_8086);
225
226 /* mask all interrupts */
227 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
228 (sc->sc_imask >> 8) & 0xff);
229
230 /* enable special mask mode */
231 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
232 OCW3_SELECT | OCW3_ESMM | OCW3_SMM);
233
234 /* read IRR by default */
235 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
236 OCW3_SELECT | OCW3_RR_CMD(OCW3_RR_CMD_READ_IRQ));
237
238 /*
239 * Default all interrupts to edge-triggered.
240 */
241 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
242 sc->sc_elcr & 0xff);
243 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
244 (sc->sc_elcr >> 8) & 0xff);
245
246 /*
247 * Some ISA interrupts are reserved for devices that
248 * we know are hard-wired to certain IRQs.
249 */
250 sc->sc_reserved =
251 (1U << 0) | /* timer */
252 (1U << 1) | /* keyboard controller */
253 (1U << 3) | /* COM 2 */
254 (1U << 4) | /* COM 1 */
255 (1U << 6) | /* floppy */
256 (1U << 7) | /* centronics */
257 (1U << 8) | /* RTC */
258 (1U << 12) | /* keyboard controller */
259 (1U << 14) | /* IDE 0 */
260 (1U << 15); /* IDE 1 */
261
262 #if defined(ALGOR_P5064)
263 /*
264 * Some "ISA" interrupts are a little wacky, wired up directly
265 * to the P-5064 interrupt controller.
266 */
267 sc->sc_parent_ic = &p5064_configuration.ac_ic;
268 #endif /* ALGOR_P5064 */
269
270 /* Set up our ISA chipset. */
271 sc->sc_ic.ic_v = sc;
272 sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
273 sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
274 sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
275 sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
276
277 /* Initialize our interrupt table. */
278 for (i = 0; i < 16; i++) {
279 LIST_INIT(&sc->sc_intrtab[i].intr_q);
280 evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
281 EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
282 sc->sc_intrtab[i].intr_type = IST_NONE;
283 }
284
285 /* Hook up our interrupt handler. */
286 #if defined(ALGOR_P5064)
287 sc->sc_ih = (*algor_intr_establish)(P5064_IRQ_ISABRIDGE,
288 pcib_intr, sc);
289 #elif defined(ALGOR_P6032)
290 sc->sc_ih = (*algor_intr_establish)(XXX,
291 pcib_intr, sc);
292 #endif
293 if (sc->sc_ih == NULL)
294 printf("%s: WARNING: unable to register interrupt handler\n",
295 sc->sc_dev.dv_xname);
296
297 config_defer(self, pcib_bridge_callback);
298 }
299
300 void
301 pcib_bridge_callback(self)
302 struct device *self;
303 {
304 struct pcib_softc *sc = (struct pcib_softc *)self;
305 struct isabus_attach_args iba;
306
307 memset(&iba, 0, sizeof(iba));
308
309 iba.iba_busname = "isa";
310 #if defined(ALGOR_P5064)
311 {
312 struct p5064_config *acp = &p5064_configuration;
313
314 iba.iba_iot = &acp->ac_iot;
315 iba.iba_memt = &acp->ac_memt;
316 iba.iba_dmat = &acp->ac_isa_dmat;
317 }
318 #elif defined(ALGOR_P6032)
319 {
320 /* XXX */
321 }
322 #endif
323
324 iba.iba_ic = &sc->sc_ic;
325 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
326
327 (void) config_found(&sc->sc_dev, &iba, pcib_print);
328 }
329
330 int
331 pcib_print(void *aux, const char *pnp)
332 {
333 struct isabus_attach_args *iba;
334
335 if (pnp)
336 printf("%s at %s", iba->iba_busname, pnp);
337 return (UNCONF);
338 }
339
340 void
341 pcib_isa_attach_hook(struct device *parent, struct device *self,
342 struct isabus_attach_args *iba)
343 {
344
345 /* Nothing to do. */
346 }
347
348 void
349 pcib_set_icus(struct pcib_softc *sc)
350 {
351
352 /* Enable the cascade IRQ (2) if 8-15 is enabled. */
353 if ((sc->sc_imask & 0xff00) != 0xff00)
354 sc->sc_imask &= ~(1U << 2);
355 else
356 sc->sc_imask |= (1U << 2);
357
358 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
359 sc->sc_imask & 0xff);
360 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
361 (sc->sc_imask >> 8) & 0xff);
362
363 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
364 sc->sc_elcr & 0xff);
365 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
366 (sc->sc_elcr >> 8) & 0xff);
367 }
368
369 int
370 pcib_intr(void *v)
371 {
372 struct pcib_softc *sc = v;
373 struct algor_intrhand *ih;
374 int irq;
375
376 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
377 OCW3_SELECT | OCW3_POLL);
378 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1,
379 PIC_OCW3) & 0x7f;
380
381 if (irq == 2) {
382 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
383 OCW3_SELECT | OCW3_POLL);
384 irq = (bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
385 PIC_OCW3) & 0x7f) + 8;
386 }
387
388 sc->sc_intrtab[irq].intr_count.ev_count++;
389 for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
390 ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
391 (*ih->ih_func)(ih->ih_arg);
392 }
393
394 /* Send a specific EOI to the 8259. */
395 if (irq > 7)
396 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
397 PIC_OCW2, OCW2_SELECT | OCW2_OP(OCW2_OP_SPECIFIC_EOI_CMD) |
398 OCW2_ILS(irq & 7));
399
400 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
401 OCW2_SELECT | OCW2_OP(OCW2_OP_SPECIFIC_EOI_CMD) |
402 (irq > 7 ? OCW2_ILS(2) : OCW2_ILS(irq)));
403
404 return (1);
405 }
406
407 const struct evcnt *
408 pcib_isa_intr_evcnt(void *v, int irq)
409 {
410 struct pcib_softc *sc = v;
411
412 #if defined(ALGOR_P5064)
413 if (p5064_isa_to_irqmap[irq] != -1)
414 return (isa_intr_evcnt(sc->sc_parent_ic, irq));
415 #endif
416
417 return (&sc->sc_intrtab[irq].intr_count);
418 }
419
420 void *
421 pcib_isa_intr_establish(void *v, int irq, int type, int level,
422 int (*func)(void *), void *arg)
423 {
424 struct pcib_softc *sc = v;
425 struct algor_intrhand *ih;
426 int s;
427
428 if (irq > 15 || irq == 2 || type == IST_NONE)
429 panic("pcib_isa_intr_establish: bad irq or type");
430
431 #if defined(ALGOR_P5064)
432 if (p5064_isa_to_irqmap[irq] != -1)
433 return (isa_intr_establish(sc->sc_parent_ic, irq, type,
434 level, func, arg));
435 #endif
436
437 switch (sc->sc_intrtab[irq].intr_type) {
438 case IST_NONE:
439 sc->sc_intrtab[irq].intr_type = type;
440 break;
441
442 case IST_EDGE:
443 case IST_LEVEL:
444 if (type == sc->sc_intrtab[irq].intr_type)
445 break;
446 /* FALLTHROUGH */
447 case IST_PULSE:
448 /*
449 * We can't share interrupts in this case.
450 */
451 return (NULL);
452 }
453
454 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
455 if (ih == NULL)
456 return (NULL);
457
458 ih->ih_func = func;
459 ih->ih_arg = arg;
460 ih->ih_irq = irq;
461 ih->ih_irqmap = NULL;
462
463 s = splhigh();
464
465 /* Insert the handler into the table. */
466 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
467 sc->sc_intrtab[irq].intr_type = type;
468
469 /* Enable it, set trigger mode. */
470 sc->sc_imask &= ~(1 << irq);
471 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
472 sc->sc_elcr |= (1 << irq);
473 else
474 sc->sc_elcr &= ~(1 << irq);
475
476 pcib_set_icus(sc);
477
478 splx(s);
479
480 return (ih);
481 }
482
483 void
484 pcib_isa_intr_disestablish(void *v, void *arg)
485 {
486 struct pcib_softc *sc = v;
487 struct algor_intrhand *ih = arg;
488 int s;
489
490 #if defined(ALGOR_P5064)
491 if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
492 isa_intr_disestablish(sc->sc_parent_ic, ih);
493 return;
494 }
495 #endif
496
497 s = splhigh();
498
499 LIST_REMOVE(ih, ih_q);
500
501 /* If there are no more handlers on this IRQ, disable it. */
502 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
503 sc->sc_imask |= (1 << ih->ih_irq);
504 pcib_set_icus(sc);
505 }
506
507 splx(s);
508
509 free(ih, M_DEVBUF);
510 }
511
512 int
513 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
514 {
515 struct pcib_softc *sc = v;
516 int i, tmp, bestirq, count;
517 struct algor_intrhand *ih;
518
519 if (type == IST_NONE)
520 panic("pcib_intr_alloc: bogus type");
521
522 bestirq = -1;
523 count = -1;
524
525 #if defined(ALGOR_P5064)
526 mask &= ~sc->sc_reserved;
527 #endif
528
529 #if 0
530 printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
531 #endif
532
533 for (i = 0; i < 16; i++) {
534 if (i == 2 || (mask & (1 << i)) == 0)
535 continue;
536
537 switch (sc->sc_intrtab[i].intr_type) {
538 case IST_NONE:
539 /*
540 * If nothing's using the IRQ, just return it.
541 */
542 *irq = i;
543 return (0);
544
545 case IST_EDGE:
546 case IST_LEVEL:
547 if (type != sc->sc_intrtab[i].intr_type)
548 continue;
549 /*
550 * If the IRQ is sharable, count the number of
551 * other handlers, and if it's smaller than the
552 * last IRQ like this, remember it.
553 */
554 tmp = 0;
555 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
556 ih != NULL; ih = LIST_NEXT(ih, ih_q))
557 tmp++;
558 if (bestirq == -1 || count > tmp) {
559 bestirq = i;
560 count = tmp;
561 }
562 break;
563
564 case IST_PULSE:
565 /* This just isn't sharable. */
566 continue;
567 }
568 }
569
570 if (bestirq == -1)
571 return (1);
572
573 *irq = bestirq;
574 return (0);
575 }
576