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