xref: /netbsd-src/sys/arch/algor/pci/pcib.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /*	$NetBSD: pcib.c,v 1.20 2009/03/14 15:35:59 dsl 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.20 2009/03/14 15:35:59 dsl 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(struct device *self)
293 {
294 	struct pcib_softc *sc = (struct pcib_softc *)self;
295 	struct isabus_attach_args iba;
296 
297 	memset(&iba, 0, sizeof(iba));
298 
299 #if defined(ALGOR_P5064)
300 	    {
301 		struct p5064_config *acp = &p5064_configuration;
302 
303 		iba.iba_iot = &acp->ac_iot;
304 		iba.iba_memt = &acp->ac_memt;
305 		iba.iba_dmat = &acp->ac_isa_dmat;
306 	    }
307 #elif defined(ALGOR_P6032)
308 	    {
309 		struct p6032_config *acp = &p6032_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 #endif
316 
317 	iba.iba_ic = &sc->sc_ic;
318 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
319 
320 	(void) config_found_ia(&sc->sc_dev, "isabus", &iba, isabusprint);
321 }
322 
323 void
324 pcib_isa_attach_hook(struct device *parent, struct device *self,
325     struct isabus_attach_args *iba)
326 {
327 
328 	/* Nothing to do. */
329 }
330 
331 void
332 pcib_set_icus(struct pcib_softc *sc)
333 {
334 
335 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
336 	if ((sc->sc_imask & 0xff00) != 0xff00)
337 		sc->sc_imask &= ~(1U << 2);
338 	else
339 		sc->sc_imask |= (1U << 2);
340 
341 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
342 	    sc->sc_imask & 0xff);
343 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
344 	    (sc->sc_imask >> 8) & 0xff);
345 
346 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
347 	    sc->sc_elcr & 0xff);
348 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
349 	    (sc->sc_elcr >> 8) & 0xff);
350 }
351 
352 int
353 pcib_intr(void *v)
354 {
355 	struct pcib_softc *sc = v;
356 	struct algor_intrhand *ih;
357 	int irq;
358 
359 	for (;;) {
360 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
361 		    OCW3_SELECT | OCW3_POLL);
362 		irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
363 		if ((irq & OCW3_POLL_PENDING) == 0)
364 			return (1);
365 
366 		irq = OCW3_POLL_IRQ(irq);
367 
368 		if (irq == 2) {
369 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
370 			    PIC_OCW3, OCW3_SELECT | OCW3_POLL);
371 			irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
372 			    PIC_OCW3);
373 			if (irq & OCW3_POLL_PENDING)
374 				irq = OCW3_POLL_IRQ(irq) + 8;
375 			else
376 				irq = 2;
377 		}
378 
379 		sc->sc_intrtab[irq].intr_count.ev_count++;
380 		for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
381 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
382 			(*ih->ih_func)(ih->ih_arg);
383 		}
384 
385 		/* Send a specific EOI to the 8259. */
386 		if (irq > 7) {
387 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
388 			    PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
389 			    OCW2_ILS(irq & 7));
390 			irq = 2;
391 		}
392 
393 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
394 		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
395 	}
396 }
397 
398 const struct evcnt *
399 pcib_isa_intr_evcnt(void *v, int irq)
400 {
401 	struct pcib_softc *sc = v;
402 
403 #if defined(ALGOR_P5064)
404 	if (p5064_isa_to_irqmap[irq] != -1)
405 		return (isa_intr_evcnt(sc->sc_parent_ic, irq));
406 #endif
407 
408 	return (&sc->sc_intrtab[irq].intr_count);
409 }
410 
411 void *
412 pcib_isa_intr_establish(void *v, int irq, int type, int level,
413     int (*func)(void *), void *arg)
414 {
415 	struct pcib_softc *sc = v;
416 	struct algor_intrhand *ih;
417 	int s;
418 
419 	if (irq > 15 || irq == 2 || type == IST_NONE)
420 		panic("pcib_isa_intr_establish: bad irq or type");
421 
422 #if defined(ALGOR_P5064)
423 	if (p5064_isa_to_irqmap[irq] != -1)
424 		return (isa_intr_establish(sc->sc_parent_ic, irq, type,
425 		    level, func, arg));
426 #endif
427 
428 	switch (sc->sc_intrtab[irq].intr_type) {
429 	case IST_NONE:
430 		sc->sc_intrtab[irq].intr_type = type;
431 		break;
432 
433 	case IST_EDGE:
434 	case IST_LEVEL:
435 		if (type == sc->sc_intrtab[irq].intr_type)
436 			break;
437 		/* FALLTHROUGH */
438 	case IST_PULSE:
439 		/*
440 		 * We can't share interrupts in this case.
441 		 */
442 		return (NULL);
443 	}
444 
445 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
446 	if (ih == NULL)
447 		return (NULL);
448 
449 	ih->ih_func = func;
450 	ih->ih_arg = arg;
451 	ih->ih_irq = irq;
452 	ih->ih_irqmap = NULL;
453 
454 	s = splhigh();
455 
456 	/* Insert the handler into the table. */
457 	LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
458 	sc->sc_intrtab[irq].intr_type = type;
459 
460 	/* Enable it, set trigger mode. */
461 	sc->sc_imask &= ~(1 << irq);
462 	if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
463 		sc->sc_elcr |= (1 << irq);
464 	else
465 		sc->sc_elcr &= ~(1 << irq);
466 
467 	pcib_set_icus(sc);
468 
469 	splx(s);
470 
471 	return (ih);
472 }
473 
474 void
475 pcib_isa_intr_disestablish(void *v, void *arg)
476 {
477 	struct pcib_softc *sc = v;
478 	struct algor_intrhand *ih = arg;
479 	int s;
480 
481 #if defined(ALGOR_P5064)
482 	if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
483 		isa_intr_disestablish(sc->sc_parent_ic, ih);
484 		return;
485 	}
486 #endif
487 
488 	s = splhigh();
489 
490 	LIST_REMOVE(ih, ih_q);
491 
492 	/* If there are no more handlers on this IRQ, disable it. */
493 	if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
494 		sc->sc_imask |= (1 << ih->ih_irq);
495 		pcib_set_icus(sc);
496 	}
497 
498 	splx(s);
499 
500 	free(ih, M_DEVBUF);
501 }
502 
503 int
504 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
505 {
506 	struct pcib_softc *sc = v;
507 	int i, tmp, bestirq, count;
508 	struct algor_intrhand *ih;
509 
510 	if (type == IST_NONE)
511 		panic("pcib_intr_alloc: bogus type");
512 
513 	bestirq = -1;
514 	count = -1;
515 
516 	mask &= ~sc->sc_reserved;
517 
518 #if 0
519 	printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
520 #endif
521 
522 	for (i = 0; i < 16; i++) {
523 		if ((mask & (1 << i)) == 0)
524 			continue;
525 
526 		switch (sc->sc_intrtab[i].intr_type) {
527 		case IST_NONE:
528 			/*
529 			 * If nothing's using the IRQ, just return it.
530 			 */
531 			*irq = i;
532 			return (0);
533 
534 		case IST_EDGE:
535 		case IST_LEVEL:
536 			if (type != sc->sc_intrtab[i].intr_type)
537 				continue;
538 			/*
539 			 * If the IRQ is sharable, count the number of
540 			 * other handlers, and if it's smaller than the
541 			 * last IRQ like this, remember it.
542 			 */
543 			tmp = 0;
544 			for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
545 			     ih != NULL; ih = LIST_NEXT(ih, ih_q))
546 				tmp++;
547 			if (bestirq == -1 || count > tmp) {
548 				bestirq = i;
549 				count = tmp;
550 			}
551 			break;
552 
553 		case IST_PULSE:
554 			/* This just isn't sharable. */
555 			continue;
556 		}
557 	}
558 
559 	if (bestirq == -1)
560 		return (1);
561 
562 	*irq = bestirq;
563 	return (0);
564 }
565