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