xref: /netbsd/sys/arch/algor/algor/algor_p5064_intr.c (revision bf9ec67e)
1 /*	$NetBSD: algor_p5064_intr.c,v 1.9 2001/10/29 23:33:42 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 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 /*
40  * Platform-specific interrupt support for the Algorithmics P-5064.
41  *
42  * The Algorithmics P-5064 has an interrupt controller that is pretty
43  * flexible -- it can take an interrupt source and route it to an
44  * arbitrary MIPS CPU hardware interrupt pin.
45  */
46 
47 #include "opt_ddb.h"
48 
49 #include <sys/param.h>
50 #include <sys/queue.h>
51 #include <sys/malloc.h>
52 #include <sys/systm.h>
53 #include <sys/device.h>
54 #include <sys/kernel.h>
55 
56 #include <machine/bus.h>
57 #include <machine/autoconf.h>
58 #include <machine/intr.h>
59 
60 #include <mips/locore.h>
61 
62 #include <dev/ic/mc146818reg.h>
63 
64 #include <algor/algor/algor_p5064reg.h>
65 #include <algor/algor/algor_p5064var.h>
66 
67 #include <algor/algor/clockvar.h>
68 
69 #include <dev/pci/pcireg.h>
70 #include <dev/pci/pcivar.h>
71 #include <dev/pci/pciidereg.h>
72 #include <dev/pci/pciidevar.h>
73 
74 #include <dev/isa/isavar.h>
75 
76 #define	REGVAL(x)	*((__volatile u_int32_t *)(MIPS_PHYS_TO_KSEG1((x))))
77 
78 struct p5064_irqreg {
79 	bus_addr_t	addr;
80 	u_int32_t	val;
81 };
82 
83 #define	IRQREG_LOCINT		0
84 #define	IRQREG_PANIC		1
85 #define	IRQREG_PCIINT		2
86 #define	IRQREG_ISAINT		3
87 #define	IRQREG_KBDINT		4
88 #define	NIRQREG			5
89 
90 struct p5064_irqreg p5064_irqregs[NIRQREG] = {
91 	{ P5064_LOCINT,		0 },
92 	{ P5064_PANIC,		0 },
93 	{ P5064_PCIINT,		0 },
94 	{ P5064_ISAINT,		0 },
95 	{ P5064_KBDINT,		0 },
96 };
97 
98 #define	NSTEERREG		5
99 
100 struct p5064_irqreg p5064_irqsteer[NSTEERREG] = {
101 	{ P5064_XBAR0,		0 },
102 	{ P5064_XBAR1,		0 },
103 	{ P5064_XBAR2,		0 },
104 	{ P5064_XBAR3,		0 },
105 	{ P5064_XBAR4,		0 },
106 };
107 
108 #define	NPCIIRQS		7
109 
110 #define	NLOCIRQS		6
111 
112 #define	NISAIRQS		3
113 
114 #define	IRQMAP_PCIBASE		0
115 #define	IRQMAP_LOCBASE		NPCIIRQS
116 #define	IRQMAP_ISABASE		(IRQMAP_LOCBASE + NLOCIRQS)
117 #define	NIRQMAPS		(IRQMAP_ISABASE + NISAIRQS)
118 
119 const char *p5064_intrnames[NIRQMAPS] = {
120 	/*
121 	 * PCI INTERRUPTS
122 	 */
123 	"PCIIRQ 0",
124 	"PCIIRQ 1",
125 	"PCIIRQ 2",
126 	"PCIIRQ 3",
127 	"Ethernet IRQ",
128 	"SCSI IRQ",
129 	"USB IRQ",
130 
131 	/*
132 	 * LOCAL INTERRUPTS
133 	 */
134 	"mkbd",
135 	"com 1",
136 	"com 2",
137 	"floppy",
138 	"centronics",
139 	"mcclock",
140 
141 	/*
142 	 * ISA interrupts.
143 	 */
144 	"bridge",
145 	"IDE primary",
146 	"IDE secondary",
147 };
148 
149 struct p5064_irqmap {
150 	int	irqidx;
151 	int	cpuintr;
152 	int	irqreg;
153 	int	irqbit;
154 	int	xbarreg;
155 	int	xbarshift;
156 };
157 
158 const struct p5064_irqmap p5064_irqmap[NIRQMAPS] = {
159 	/*
160 	 * PCI INTERRUPTS
161 	 */
162 	/* PCIIRQ 0 */
163 	{ 0,			1,
164 	  IRQREG_PCIINT,	PCIINT_PCI0,
165 	  2,			0 },
166 
167 	/* PCIIRQ 1 */
168 	{ 1,			1,
169 	  IRQREG_PCIINT,	PCIINT_PCI1,
170 	  2,			2 },
171 
172 	/* PCIIRQ 2 */
173 	{ 2,			1,
174 	  IRQREG_PCIINT,	PCIINT_PCI2,
175 	  2,			4 },
176 
177 	/* PCIIRQ 3 */
178 	{ 3,			1,
179 	  IRQREG_PCIINT,	PCIINT_PCI3,
180 	  2,			6 },
181 
182 	/* Ethernet */
183 	{ P5064_IRQ_ETHERNET,	1,
184 	  IRQREG_PCIINT,	PCIINT_ETH,
185 	  4,			2 },
186 
187 	/* SCSI */
188 	{ P5064_IRQ_SCSI,	1,
189 	  IRQREG_PCIINT,	PCIINT_SCSI,
190 	  4,			4 },
191 
192 	/* USB */
193 	{ P5064_IRQ_USB,	1,
194 	  IRQREG_PCIINT,	PCIINT_USB,
195 	  4,			6 },
196 
197 	/*
198 	 * LOCAL INTERRUPTS
199 	 */
200 	/* keyboard */
201 	{ P5064_IRQ_MKBD,	2,
202 	  IRQREG_LOCINT,	LOCINT_MKBD,
203 	  0,			4 },
204 
205 	/* COM1 */
206 	{ P5064_IRQ_COM1,	2,
207 	  IRQREG_LOCINT,	LOCINT_COM1,
208 	  0,			6 },
209 
210 	/* COM2 */
211 	{ P5064_IRQ_COM2,	2,
212 	  IRQREG_LOCINT,	LOCINT_COM2,
213 	  1,			0 },
214 
215 	/* floppy controller */
216 	{ P5064_IRQ_FLOPPY,	2,
217 	  IRQREG_LOCINT,	LOCINT_FLP,
218 	  0,			2 },
219 
220 	/* parallel port */
221 	{ P5064_IRQ_CENTRONICS,	2,
222 	  IRQREG_LOCINT,	LOCINT_CENT,
223 	  1,			2 },
224 
225 	/* RTC */
226 	{ P5064_IRQ_RTC,	2,
227 	  IRQREG_LOCINT,	LOCINT_RTC,
228 	  1,			6 },
229 
230 	/*
231 	 * ISA INTERRUPTS
232 	 */
233 	/* ISA bridge */
234 	{ P5064_IRQ_ISABRIDGE,	0,
235 	  IRQREG_ISAINT,	ISAINT_ISABR,
236 	  3,			0 },
237 
238 	/* IDE 0 */
239 	{ P5064_IRQ_IDE0,	0,
240 	  IRQREG_ISAINT,	ISAINT_IDE0,
241 	  3,			2 },
242 
243 	/* IDE 1 */
244 	{ P5064_IRQ_IDE1,	0,
245 	  IRQREG_ISAINT,	ISAINT_IDE1,
246 	  3,			4 },
247 };
248 
249 const int p5064_isa_to_irqmap[16] = {
250 	-1,			/* 0 */
251 	P5064_IRQ_MKBD,		/* 1 */
252 	-1,			/* 2 */
253 	P5064_IRQ_COM2,		/* 3 */
254 	P5064_IRQ_COM1,		/* 4 */
255 	-1,			/* 5 */
256 	P5064_IRQ_FLOPPY,	/* 6 */
257 	P5064_IRQ_CENTRONICS,	/* 7 */
258 	P5064_IRQ_RTC,		/* 8 */
259 	-1,			/* 9 */
260 	-1,			/* 10 */
261 	-1,			/* 11 */
262 	P5064_IRQ_MKBD,		/* 12 */
263 	-1,			/* 13 */
264 	P5064_IRQ_IDE0,		/* 14 */
265 	P5064_IRQ_IDE1,		/* 15 */
266 };
267 
268 struct p5064_intrhead {
269 	struct evcnt intr_count;
270 	int intr_refcnt;
271 };
272 struct p5064_intrhead p5064_intrtab[NIRQMAPS];
273 
274 #define	NINTRS			3	/* MIPS INT0 - INT2 */
275 
276 struct p5064_cpuintr {
277 	LIST_HEAD(, algor_intrhand) cintr_list;
278 	struct evcnt cintr_count;
279 };
280 
281 struct p5064_cpuintr p5064_cpuintrs[NINTRS];
282 const char *p5064_cpuintrnames[NINTRS] = {
283 	"int 0 (isa)",
284 	"int 1 (pci)",
285 	"int 2 (local)",
286 };
287 
288 const char *p5064_intrgroups[NINTRS] = {
289 	"isa",
290 	"pci",
291 	"local",
292 };
293 
294 void	*algor_p5064_intr_establish(int, int (*)(void *), void *);
295 void	algor_p5064_intr_disestablish(void *);
296 
297 int	algor_p5064_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
298 const char *algor_p5064_pci_intr_string(void *, pci_intr_handle_t);
299 const struct evcnt *algor_p5064_pci_intr_evcnt(void *, pci_intr_handle_t);
300 void	*algor_p5064_pci_intr_establish(void *, pci_intr_handle_t, int,
301 	    int (*)(void *), void *);
302 void	algor_p5064_pci_intr_disestablish(void *, void *);
303 void	*algor_p5064_pciide_compat_intr_establish(void *, struct device *,
304 	    struct pci_attach_args *, int, int (*)(void *), void *);
305 void	algor_p5064_pci_conf_interrupt(void *, int, int, int, int, int *);
306 
307 const struct evcnt *algor_p5064_isa_intr_evcnt(void *, int);
308 void	*algor_p5064_isa_intr_establish(void *, int, int, int,
309 	    int (*)(void *), void *);
310 void	algor_p5064_isa_intr_disestablish(void *, void *);
311 int	algor_p5064_isa_intr_alloc(void *, int, int, int *);
312 
313 void	algor_p5064_iointr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
314 
315 void
316 algor_p5064_intr_init(struct p5064_config *acp)
317 {
318 	const struct p5064_irqmap *irqmap;
319 	int i;
320 
321 	for (i = 0; i < NIRQREG; i++)
322 		REGVAL(p5064_irqregs[i].addr) = p5064_irqregs[i].val;
323 
324 	for (i = 0; i < NINTRS; i++) {
325 		LIST_INIT(&p5064_cpuintrs[i].cintr_list);
326 		evcnt_attach_dynamic(&p5064_cpuintrs[i].cintr_count,
327 		    EVCNT_TYPE_INTR, NULL, "mips", p5064_cpuintrnames[i]);
328 	}
329 	evcnt_attach_static(&mips_int5_evcnt);
330 
331 	for (i = 0; i < NIRQMAPS; i++) {
332 		irqmap = &p5064_irqmap[i];
333 
334 		p5064_irqsteer[irqmap->xbarreg].val |=
335 		    irqmap->cpuintr << irqmap->xbarshift;
336 
337 		evcnt_attach_dynamic(&p5064_intrtab[i].intr_count,
338 		    EVCNT_TYPE_INTR, NULL, p5064_intrgroups[irqmap->cpuintr],
339 		    p5064_intrnames[i]);
340 	}
341 
342 	for (i = 0; i < NSTEERREG; i++)
343 		REGVAL(p5064_irqsteer[i].addr) = p5064_irqsteer[i].val;
344 
345 	acp->ac_pc.pc_intr_v = NULL;
346 	acp->ac_pc.pc_intr_map = algor_p5064_pci_intr_map;
347 	acp->ac_pc.pc_intr_string = algor_p5064_pci_intr_string;
348 	acp->ac_pc.pc_intr_evcnt = algor_p5064_pci_intr_evcnt;
349 	acp->ac_pc.pc_intr_establish = algor_p5064_pci_intr_establish;
350 	acp->ac_pc.pc_intr_disestablish = algor_p5064_pci_intr_disestablish;
351 	acp->ac_pc.pc_conf_interrupt = algor_p5064_pci_conf_interrupt;
352 	acp->ac_pc.pc_pciide_compat_intr_establish =
353 	    algor_p5064_pciide_compat_intr_establish;
354 
355 	acp->ac_ic.ic_v = NULL;
356 	acp->ac_ic.ic_intr_evcnt = algor_p5064_isa_intr_evcnt;
357 	acp->ac_ic.ic_intr_establish = algor_p5064_isa_intr_establish;
358 	acp->ac_ic.ic_intr_disestablish = algor_p5064_isa_intr_disestablish;
359 	acp->ac_ic.ic_intr_alloc = algor_p5064_isa_intr_alloc;
360 
361 	algor_intr_establish = algor_p5064_intr_establish;
362 	algor_intr_disestablish = algor_p5064_intr_disestablish;
363 	algor_iointr = algor_p5064_iointr;
364 }
365 
366 void
367 algor_p5064_cal_timer(bus_space_tag_t st, bus_space_handle_t sh)
368 {
369 	u_long ctrdiff[4], startctr, endctr, cps;
370 	u_int32_t irr;
371 	int i;
372 
373 	/* Disable interrupts first. */
374 	bus_space_write_1(st, sh, 0, MC_REGB);
375 	bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
376 	    MC_REGB_24HR);
377 
378 	/* Initialize for 16Hz. */
379 	bus_space_write_1(st, sh, 0, MC_REGA);
380 	bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz);
381 
382 	REGVAL(P5064_LOCINT) = LOCINT_RTC;
383 
384 	/* Run the loop an extra time to prime the cache. */
385 	for (i = 0; i < 4; i++) {
386 		led_display('h', 'z', '0' + i, ' ');
387 
388 		/* Enable the interrupt. */
389 		bus_space_write_1(st, sh, 0, MC_REGB);
390 		bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE |
391 		    MC_REGB_BINARY | MC_REGB_24HR);
392 
393 		/* Wait for it to happen. */
394 		startctr = mips3_cp0_count_read();
395 		do {
396 			irr = REGVAL(P5064_LOCINT);
397 			endctr = mips3_cp0_count_read();
398 		} while ((irr & LOCINT_RTC) == 0);
399 
400 		/* ACK. */
401 		bus_space_write_1(st, sh, 0, MC_REGC);
402 		(void) bus_space_read_1(st, sh, 1);
403 
404 		/* Disable. */
405 		bus_space_write_1(st, sh, 0, MC_REGB);
406 		bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
407 		    MC_REGB_24HR);
408 
409 		ctrdiff[i] = endctr - startctr;
410 	}
411 
412 	REGVAL(P5064_LOCINT) = 0;
413 
414 	/* Compute the number of cycles per second. */
415 	cps = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
416 
417 	/* Compute the number of ticks for hz. */
418 	cycles_per_hz = cps / hz;
419 
420 	/* Compute the delay divisor. */
421 	delay_divisor = (cps / 1000000) / 2;
422 
423 	printf("Timer calibration: %lu cycles/sec [(%lu, %lu) * 16]\n",
424 	    cps, ctrdiff[2], ctrdiff[3]);
425 	printf("CPU clock speed = %lu.%02luMHz "
426 	    "(hz cycles = %lu, delay divisor = %u)\n",
427 	    cps / 1000000, (cps % 1000000) / 10000,
428 	    cycles_per_hz, delay_divisor);
429 }
430 
431 void *
432 algor_p5064_intr_establish(int irq, int (*func)(void *), void *arg)
433 {
434 	const struct p5064_irqmap *irqmap;
435 	struct algor_intrhand *ih;
436 	int s;
437 
438 	irqmap = &p5064_irqmap[irq];
439 
440 	KASSERT(irq == irqmap->irqidx);
441 
442 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
443 	if (ih == NULL)
444 		return (NULL);
445 
446 	ih->ih_func = func;
447 	ih->ih_arg = arg;
448 	ih->ih_irq = 0;
449 	ih->ih_irqmap = irqmap;
450 
451 	s = splhigh();
452 
453 	/*
454 	 * First, link it into the tables.
455 	 */
456 	LIST_INSERT_HEAD(&p5064_cpuintrs[irqmap->cpuintr].cintr_list,
457 	    ih, ih_q);
458 
459 	/*
460 	 * Now enable it.
461 	 */
462 	if (p5064_intrtab[irqmap->irqidx].intr_refcnt++ == 0) {
463 		p5064_irqregs[irqmap->irqreg].val |= irqmap->irqbit;
464 		REGVAL(p5064_irqregs[irqmap->irqreg].addr) =
465 		    p5064_irqregs[irqmap->irqreg].val;
466 	}
467 
468 	splx(s);
469 
470 	return (ih);
471 }
472 
473 void
474 algor_p5064_intr_disestablish(void *cookie)
475 {
476 	const struct p5064_irqmap *irqmap;
477 	struct algor_intrhand *ih = cookie;
478 	int s;
479 
480 	irqmap = ih->ih_irqmap;
481 
482 	s = splhigh();
483 
484 	/*
485 	 * First, remove it from the table.
486 	 */
487 	LIST_REMOVE(ih, ih_q);
488 
489 	/*
490 	 * Now, disable it, if there is nothing remaining on the
491 	 * list.
492 	 */
493 	if (p5064_intrtab[irqmap->irqidx].intr_refcnt-- == 1) {
494 		p5064_irqregs[irqmap->irqreg].val &= ~irqmap->irqbit;
495 		REGVAL(p5064_irqregs[irqmap->irqreg].addr) =
496 		    p5064_irqregs[irqmap->irqreg].val;
497 	}
498 
499 	splx(s);
500 
501 	free(ih, M_DEVBUF);
502 }
503 
504 void
505 algor_p5064_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc,
506     u_int32_t ipending)
507 {
508 	const struct p5064_irqmap *irqmap;
509 	struct algor_intrhand *ih;
510 	int level, i;
511 	u_int32_t irr[NIRQREG];
512 
513 	/* Check for PANIC interrupts. */
514 	if (ipending & MIPS_INT_MASK_4) {
515 		irr[IRQREG_PANIC] = REGVAL(p5064_irqregs[IRQREG_PANIC].addr);
516 		if (irr[IRQREG_PANIC] & PANIC_IOPERR)
517 			printf("WARNING: I/O parity error\n");
518 		if (irr[IRQREG_PANIC] & PANIC_ISANMI)
519 			printf("WARNING: ISA NMI\n");
520 		if (irr[IRQREG_PANIC] & PANIC_BERR)
521 			printf("WARNING: Bus error\n");
522 		if (irr[IRQREG_PANIC] & PANIC_PFAIL)
523 			printf("WARNING: Power failure\n");
524 		if (irr[IRQREG_PANIC] & PANIC_DEBUG) {
525 #ifdef DDB
526 			printf("Debug switch -- entering debugger\n");
527 			led_display('D','D','B',' ');
528 			Debugger();
529 			led_display('N','B','S','D');
530 #else
531 			printf("Debug switch ignored -- "
532 			    "no debugger configured\n");
533 #endif
534 		}
535 
536 		/* Clear them. */
537 		REGVAL(p5064_irqregs[IRQREG_PANIC].addr) = irr[IRQREG_PANIC];
538 	}
539 
540 	/*
541 	 * Read the interrupt pending registers, mask them with the
542 	 * ones we have enabled, and service them in order of decreasing
543 	 * priority.
544 	 */
545 	for (i = 0; i < NIRQREG; i++) {
546 		if (i == IRQREG_PANIC)
547 			continue;
548 		irr[i] = REGVAL(p5064_irqregs[i].addr) & p5064_irqregs[i].val;
549 	}
550 
551 	for (level = (NINTRS - 1); level >= 0; level--) {
552 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
553 			continue;
554 		p5064_cpuintrs[level].cintr_count.ev_count++;
555 		for (ih = LIST_FIRST(&p5064_cpuintrs[level].cintr_list);
556 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
557 			irqmap = ih->ih_irqmap;
558 			if (irr[irqmap->irqreg] & irqmap->irqbit) {
559 				p5064_intrtab[
560 				    irqmap->irqidx].intr_count.ev_count++;
561 				(*ih->ih_func)(ih->ih_arg);
562 			}
563 		}
564 		cause &= ~(MIPS_INT_MASK_0 << level);
565 	}
566 
567 	/* Re-enable anything that we have processed. */
568 	_splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
569 }
570 
571 /*****************************************************************************
572  * PCI interrupt support
573  *****************************************************************************/
574 
575 int
576 algor_p5064_pci_intr_map(struct pci_attach_args *pa,
577     pci_intr_handle_t *ihp)
578 {
579 	static const int pciirqmap[6/*device*/][4/*pin*/] = {
580 		{ P5064_IRQ_ETHERNET, -1, -1, -1 },	/* 0: Ethernet */
581 		{ P5064_IRQ_SCSI, -1, -1, -1 },		/* 1: SCSI */
582 		{ -1, -1, -1, P5064_IRQ_USB },		/* 2: PCI-ISA bridge */
583 		{ 0, 1, 2, 3 },				/* 3: PCI slot 3 */
584 		{ 3, 0, 1, 2 },				/* 4: PCI slot 2 */
585 		{ 2, 3, 0, 1 },				/* 5: PCI slot 1 */
586 	};
587 	pcitag_t bustag = pa->pa_intrtag;
588 	int buspin = pa->pa_intrpin;
589 	pci_chipset_tag_t pc = pa->pa_pc;
590 	int device, irq;
591 
592 	if (buspin == 0) {
593 		/* No IRQ used. */
594 		return (1);
595 	}
596 
597 	if (buspin > 4) {
598 		printf("algor_p5064_pci_intr_map: bad interrupt pin %d\n",
599 		    buspin);
600 		return (1);
601 	}
602 
603 	pci_decompose_tag(pc, bustag, NULL, &device, NULL);
604 	if (device > 5) {
605 		printf("algor_p5064_pci_intr_map: bad device %d\n",
606 		    device);
607 		return (1);
608 	}
609 
610 	irq = pciirqmap[device][buspin - 1];
611 	if (irq == -1) {
612 		printf("algor_p5064_pci_intr_map: no mapping for "
613 		    "device %d pin %d\n", device, buspin);
614 		return (1);
615 	}
616 
617 	*ihp = irq;
618 	return (0);
619 }
620 
621 const char *
622 algor_p5064_pci_intr_string(void *v, pci_intr_handle_t ih)
623 {
624 
625 	if (ih >= NPCIIRQS)
626 		panic("algor_p5064_intr_string: bogus IRQ %ld\n", ih);
627 
628 	return (p5064_intrnames[ih]);
629 }
630 
631 const struct evcnt *
632 algor_p5064_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
633 {
634 
635 	return (&p5064_intrtab[ih].intr_count);
636 }
637 
638 void *
639 algor_p5064_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
640     int (*func)(void *), void *arg)
641 {
642 
643 	if (ih >= NPCIIRQS)
644 		panic("algor_p5064_intr_establish: bogus IRQ %ld\n", ih);
645 
646 	return (algor_p5064_intr_establish(ih, func, arg));
647 }
648 
649 void
650 algor_p5064_pci_intr_disestablish(void *v, void *cookie)
651 {
652 
653 	return (algor_p5064_intr_disestablish(cookie));
654 }
655 
656 void
657 algor_p5064_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
658     int *iline)
659 {
660 
661 	/*
662 	 * We actually don't need to do anything; everything is handled
663 	 * in pci_intr_map().
664 	 */
665 	*iline = 0;
666 }
667 
668 void *
669 algor_p5064_pciide_compat_intr_establish(void *v, struct device *dev,
670     struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
671 {
672 	pci_chipset_tag_t pc = pa->pa_pc;
673 	void *cookie;
674 	int bus;
675 
676 	pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
677 
678 	/*
679 	 * If this isn't PCI bus #0, all bets are off.
680 	 */
681 	if (bus != 0)
682 		return (NULL);
683 
684 	cookie = algor_p5064_intr_establish(P5064_IRQ_IDE0 + chan, func, arg);
685 	if (cookie == NULL)
686 		return (NULL);
687 	printf("%s: %s channel interrupting at on-board %s IRQ\n",
688 	    dev->dv_xname, PCIIDE_CHANNEL_NAME(chan),
689 	    p5064_intrnames[P5064_IRQ_IDE0 + chan]);
690 	return (cookie);
691 }
692 
693 /*****************************************************************************
694  * ISA interrupt support
695  *****************************************************************************/
696 
697 const struct evcnt *
698 algor_p5064_isa_intr_evcnt(void *v, int iirq)
699 {
700 
701 	/* XXX */
702 	return (NULL);
703 }
704 
705 void *
706 algor_p5064_isa_intr_establish(void *v, int iirq, int type, int level,
707     int (*func)(void *), void *arg)
708 {
709 	struct algor_intrhand *ih;
710 	int irqidx;
711 
712 	if (iirq > 15 || type == IST_NONE)
713 		panic("algor_p5064_isa_intr_establish: bad irq or type");
714 
715 	if ((irqidx = p5064_isa_to_irqmap[iirq]) == -1)
716 		return (NULL);
717 
718 	ih = algor_p5064_intr_establish(irqidx, func, arg);
719 	if (ih != NULL) {
720 		/* Translate it to an ISA IRQ. */
721 		ih->ih_irq = iirq;
722 	}
723 	return (ih);
724 }
725 
726 void
727 algor_p5064_isa_intr_disestablish(void *v, void *cookie)
728 {
729 	struct algor_intrhand *ih = cookie;
730 
731 	/* Translate the IRQ back to our domain. */
732 	ih->ih_irq = p5064_isa_to_irqmap[ih->ih_irq];
733 
734 	algor_p5064_intr_disestablish(ih);
735 }
736 
737 int
738 algor_p5064_isa_intr_alloc(void *v, int mask, int type, int *iirq)
739 {
740 
741 	/* XXX */
742 	return (1);
743 }
744