pcib.c revision 1.7 1 /* $NetBSD: pcib.c,v 1.7 2001/06/21 19:00:18 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.7 2001/06/21 19:00:18 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 ICW1_SELECT | 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(2));
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_SSMM | 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);
214
215 /* reset; program device, 4 bytes */
216 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1,
217 ICW1_SELECT | ICW1_IC4);
218 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2,
219 ICW2_VECTOR(32 + 8)/*XXX*/);
220 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3,
221 ICW3_SIC(2));
222 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4,
223 ICW4_8086);
224
225 /* mask all interrupts */
226 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
227 (sc->sc_imask >> 8) & 0xff);
228
229 /* enable special mask mode */
230 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
231 OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
232
233 /* read IRR by default */
234 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
235 OCW3_SELECT | OCW3_RR);
236
237 /*
238 * Default all interrupts to edge-triggered.
239 */
240 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
241 sc->sc_elcr & 0xff);
242 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
243 (sc->sc_elcr >> 8) & 0xff);
244
245 /*
246 * Some ISA interrupts are reserved for devices that
247 * we know are hard-wired to certain IRQs.
248 */
249 sc->sc_reserved =
250 (1U << 0) | /* timer */
251 (1U << 1) | /* keyboard controller */
252 (1U << 2) | /* PIC cascade */
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 for (;;) {
377 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
378 OCW3_SELECT | OCW3_POLL);
379 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
380 if ((irq & OCW3_POLL_PENDING) == 0)
381 return (1);
382
383 irq = OCW3_POLL_IRQ(irq);
384
385 if (irq == 2) {
386 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
387 PIC_OCW3, OCW3_SELECT | OCW3_POLL);
388 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
389 PIC_OCW3);
390 if (irq & OCW3_POLL_PENDING)
391 irq = OCW3_POLL_IRQ(irq) + 8;
392 else
393 irq = 2;
394 }
395
396 sc->sc_intrtab[irq].intr_count.ev_count++;
397 for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
398 ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
399 (*ih->ih_func)(ih->ih_arg);
400 }
401
402 /* Send a specific EOI to the 8259. */
403 if (irq > 7) {
404 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
405 PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL |
406 OCW2_ILS(irq & 7));
407 irq = 2;
408 }
409
410 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
411 OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq));
412 }
413 }
414
415 const struct evcnt *
416 pcib_isa_intr_evcnt(void *v, int irq)
417 {
418 struct pcib_softc *sc = v;
419
420 #if defined(ALGOR_P5064)
421 if (p5064_isa_to_irqmap[irq] != -1)
422 return (isa_intr_evcnt(sc->sc_parent_ic, irq));
423 #endif
424
425 return (&sc->sc_intrtab[irq].intr_count);
426 }
427
428 void *
429 pcib_isa_intr_establish(void *v, int irq, int type, int level,
430 int (*func)(void *), void *arg)
431 {
432 struct pcib_softc *sc = v;
433 struct algor_intrhand *ih;
434 int s;
435
436 if (irq > 15 || irq == 2 || type == IST_NONE)
437 panic("pcib_isa_intr_establish: bad irq or type");
438
439 #if defined(ALGOR_P5064)
440 if (p5064_isa_to_irqmap[irq] != -1)
441 return (isa_intr_establish(sc->sc_parent_ic, irq, type,
442 level, func, arg));
443 #endif
444
445 switch (sc->sc_intrtab[irq].intr_type) {
446 case IST_NONE:
447 sc->sc_intrtab[irq].intr_type = type;
448 break;
449
450 case IST_EDGE:
451 case IST_LEVEL:
452 if (type == sc->sc_intrtab[irq].intr_type)
453 break;
454 /* FALLTHROUGH */
455 case IST_PULSE:
456 /*
457 * We can't share interrupts in this case.
458 */
459 return (NULL);
460 }
461
462 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
463 if (ih == NULL)
464 return (NULL);
465
466 ih->ih_func = func;
467 ih->ih_arg = arg;
468 ih->ih_irq = irq;
469 ih->ih_irqmap = NULL;
470
471 s = splhigh();
472
473 /* Insert the handler into the table. */
474 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
475 sc->sc_intrtab[irq].intr_type = type;
476
477 /* Enable it, set trigger mode. */
478 sc->sc_imask &= ~(1 << irq);
479 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
480 sc->sc_elcr |= (1 << irq);
481 else
482 sc->sc_elcr &= ~(1 << irq);
483
484 pcib_set_icus(sc);
485
486 splx(s);
487
488 return (ih);
489 }
490
491 void
492 pcib_isa_intr_disestablish(void *v, void *arg)
493 {
494 struct pcib_softc *sc = v;
495 struct algor_intrhand *ih = arg;
496 int s;
497
498 #if defined(ALGOR_P5064)
499 if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
500 isa_intr_disestablish(sc->sc_parent_ic, ih);
501 return;
502 }
503 #endif
504
505 s = splhigh();
506
507 LIST_REMOVE(ih, ih_q);
508
509 /* If there are no more handlers on this IRQ, disable it. */
510 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
511 sc->sc_imask |= (1 << ih->ih_irq);
512 pcib_set_icus(sc);
513 }
514
515 splx(s);
516
517 free(ih, M_DEVBUF);
518 }
519
520 int
521 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
522 {
523 struct pcib_softc *sc = v;
524 int i, tmp, bestirq, count;
525 struct algor_intrhand *ih;
526
527 if (type == IST_NONE)
528 panic("pcib_intr_alloc: bogus type");
529
530 bestirq = -1;
531 count = -1;
532
533 mask &= ~sc->sc_reserved;
534
535 #if 0
536 printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
537 #endif
538
539 for (i = 0; i < 16; i++) {
540 if ((mask & (1 << i)) == 0)
541 continue;
542
543 switch (sc->sc_intrtab[i].intr_type) {
544 case IST_NONE:
545 /*
546 * If nothing's using the IRQ, just return it.
547 */
548 *irq = i;
549 return (0);
550
551 case IST_EDGE:
552 case IST_LEVEL:
553 if (type != sc->sc_intrtab[i].intr_type)
554 continue;
555 /*
556 * If the IRQ is sharable, count the number of
557 * other handlers, and if it's smaller than the
558 * last IRQ like this, remember it.
559 */
560 tmp = 0;
561 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
562 ih != NULL; ih = LIST_NEXT(ih, ih_q))
563 tmp++;
564 if (bestirq == -1 || count > tmp) {
565 bestirq = i;
566 count = tmp;
567 }
568 break;
569
570 case IST_PULSE:
571 /* This just isn't sharable. */
572 continue;
573 }
574 }
575
576 if (bestirq == -1)
577 return (1);
578
579 *irq = bestirq;
580 return (0);
581 }
582