xref: /netbsd-src/sys/arch/algor/pci/pcib.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
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