/*-
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
/*
* Some ISA interrupts are reserved for devices that
* we know are hard-wired to certain IRQs.
*/
sc->sc_reserved =
(1U << 0) | /* timer */
(1U << 1) | /* keyboard controller */
(1U << 2) | /* PIC cascade */
(1U << 3) | /* COM 2 */
(1U << 4) | /* COM 1 */
(1U << 6) | /* floppy */
(1U << 7) | /* centronics */
(1U << 8) | /* RTC */
(1U << 12) | /* keyboard controller */
(1U << 14) | /* IDE 0 */
(1U << 15); /* IDE 1 */
#if defined(ALGOR_P5064)
/*
* Some "ISA" interrupts are a little wacky, wired up directly
* to the P-5064 interrupt controller.
*/
sc->sc_parent_ic = &p5064_configuration.ac_ic;
#endif /* ALGOR_P5064 */
/* Set up our ISA chipset. */
sc->sc_ic.ic_v = sc;
sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
/* Initialize our interrupt table. */
for (i = 0; i < 16; i++) {
LIST_INIT(&sc->sc_intrtab[i].intr_q);
evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
sc->sc_intrtab[i].intr_type = IST_NONE;
}
sc->sc_intrtab[irq].intr_count.ev_count++;
for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
(*ih->ih_func)(ih->ih_arg);
}
/* Send a specific EOI to the 8259. */
if (irq > 7) {
bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
OCW2_ILS(irq & 7));
irq = 2;
}
switch (sc->sc_intrtab[irq].intr_type) {
case IST_NONE:
sc->sc_intrtab[irq].intr_type = type;
break;
case IST_EDGE:
case IST_LEVEL:
if (type == sc->sc_intrtab[irq].intr_type)
break;
/* FALLTHROUGH */
case IST_PULSE:
/*
* We can't share interrupts in this case.
*/
return (NULL);
}
/* If there are no more handlers on this IRQ, disable it. */
if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
sc->sc_imask |= (1 << ih->ih_irq);
pcib_set_icus(sc);
}
splx(s);
kmem_free(ih, sizeof(*ih));
}
int
pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
{
struct pcib_softc *sc = v;
int i, tmp, bestirq, count;
struct evbmips_intrhand *ih;
if (type == IST_NONE)
panic("pcib_intr_alloc: bogus type");
for (i = 0; i < 16; i++) {
if ((mask & (1 << i)) == 0)
continue;
switch (sc->sc_intrtab[i].intr_type) {
case IST_NONE:
/*
* If nothing's using the IRQ, just return it.
*/
*irq = i;
return (0);
case IST_EDGE:
case IST_LEVEL:
if (type != sc->sc_intrtab[i].intr_type)
continue;
/*
* If the IRQ is shareable, count the number of
* other handlers, and if it's smaller than the
* last IRQ like this, remember it.
*/
tmp = 0;
for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
ih != NULL; ih = LIST_NEXT(ih, ih_q))
tmp++;
if (bestirq == -1 || count > tmp) {
bestirq = i;
count = tmp;
}
break;
case IST_PULSE:
/* This just isn't shareable. */
continue;
}
}