diff options
-rw-r--r-- | sys/ia64/acpica/madt.c | 48 | ||||
-rw-r--r-- | sys/ia64/ia64/interrupt.c | 192 | ||||
-rw-r--r-- | sys/ia64/ia64/nexus.c | 15 | ||||
-rw-r--r-- | sys/ia64/include/intr.h | 29 | ||||
-rw-r--r-- | sys/ia64/include/sapicreg.h | 48 | ||||
-rw-r--r-- | sys/ia64/include/sapicvar.h | 50 |
6 files changed, 342 insertions, 40 deletions
diff --git a/sys/ia64/acpica/madt.c b/sys/ia64/acpica/madt.c index 65581c9..81b7f59 100644 --- a/sys/ia64/acpica/madt.c +++ b/sys/ia64/acpica/madt.c @@ -94,41 +94,46 @@ typedef struct /* PLATFORM INTERRUPT SOURCE */ static void parse_interrupt_override(INTERRUPT_SOURCE_OVERRIDE *override) { - printf("\t\tBus=%d, Source=%d, Irq=0x%x\n", - override->Bus, - override->Source, - override->GlobalSystemInterrupt); + if (bootverbose) + printf("\t\tBus=%d, Source=%d, Irq=0x%x\n", + override->Bus, + override->Source, + override->GlobalSystemInterrupt); } static void parse_io_sapic(IO_SAPIC *sapic) { - printf("\t\tId=0x%x, Vector=0x%x, Address=0x%lx\n", - sapic->IoSapicId, - sapic->Vector, - sapic->IoSapicAddress); + if (bootverbose) + printf("\t\tId=0x%x, Vector=0x%x, Address=0x%lx\n", + sapic->IoSapicId, + sapic->Vector, + sapic->IoSapicAddress); + sapic_create(sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress); } static void parse_local_sapic(LOCAL_SAPIC *sapic) { - printf("\t\tProcessorId=0x%x, Id=0x%x, Eid=0x%x\n", - sapic->ProcessorId, - sapic->LocalSapicId, - sapic->LocalSapicEid); + if (bootverbose) + printf("\t\tProcessorId=0x%x, Id=0x%x, Eid=0x%x\n", + sapic->ProcessorId, + sapic->LocalSapicId, + sapic->LocalSapicEid); } static void parse_platform_interrupt(PLATFORM_INTERRUPT_SOURCE *source) { - printf("\t\tPolarity=%d, TriggerMode=%d, Id=0x%x, " - "Eid=0x%x, Vector=0x%x, Irq=%d\n", - source->Polarity, - source->TriggerMode, - source->ProcessorId, - source->ProcessorEid, - source->IoSapicVector, - source->GlobalSystemInterrupt); + if (bootverbose) + printf("\t\tPolarity=%d, TriggerMode=%d, Id=0x%x, " + "Eid=0x%x, Vector=0x%x, Irq=%d\n", + source->Polarity, + source->TriggerMode, + source->ProcessorId, + source->ProcessorEid, + source->IoSapicVector, + source->GlobalSystemInterrupt); } static void @@ -144,7 +149,8 @@ parse_madt(APIC_TABLE *madt) for (p = (char *) (madt + 1); p < end; ) { APIC_HEADER *head = (APIC_HEADER *) p; - printf("\t"); + if (bootverbose) + printf("\t"); switch (head->Type) { case APIC_PROC: if (bootverbose) diff --git a/sys/ia64/ia64/interrupt.c b/sys/ia64/ia64/interrupt.c index 8661fcd..1abe789 100644 --- a/sys/ia64/ia64/interrupt.c +++ b/sys/ia64/ia64/interrupt.c @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/proc.h> #include <sys/vmmeter.h> #include <sys/bus.h> @@ -53,6 +54,7 @@ #include <machine/reg.h> #include <machine/frame.h> #include <machine/intr.h> +#include <machine/sapicvar.h> #ifdef EVCNT_COUNTERS struct evcnt clock_intr_evcnt; /* event counter for clock intrs. */ @@ -82,12 +84,23 @@ void interrupt(u_int64_t vector, struct trapframe *framep) { struct thread *td; + volatile struct ia64_interrupt_block *ib = IA64_INTERRUPT_BLOCK; td = curthread; atomic_add_int(&td->td_intr_nesting_level, 1); - switch (vector) { - case 240: /* clock interrupt */ - CTR0(KTR_INTR, "clock interrupt"); + + /* + * Handle ExtINT interrupts by generating an INTA cycle to + * read the vector. + */ + if (vector == 0) { + vector = ib->ib_inta; + printf("ExtINT interrupt: vector=%ld\n", vector); + goto out; /* XXX */ + } + + if (vector == 240) {/* clock interrupt */ + /* CTR0(KTR_INTR, "clock interrupt"); */ cnt.v_intr++; #ifdef EVCNT_COUNTERS @@ -100,17 +113,14 @@ interrupt(u_int64_t vector, struct trapframe *framep) /* divide hz (1024) by 8 to get stathz (128) */ if((++schedclk2 & 0x7) == 0) statclock((struct clockframe *)framep); - break; - - default: - mtx_lock(&Giant); - panic("unexpected interrupt: vec %ld\n", vector); - /* NOTREACHED */ + } else { + ia64_dispatch_intr(framep, vector); } + + out: atomic_subtract_int(&td->td_intr_nesting_level, 1); } - int badaddr(addr, size) void *addr; @@ -127,3 +137,165 @@ badaddr_read(addr, size, rptr) { return (1); /* XXX implement */ } + +/* + * Hardware irqs have vectors starting at this offset. + */ +#define IA64_HARDWARE_IRQ_BASE 0x20 + +struct ia64_intr { + struct ithd *ithd; /* interrupt thread */ + volatile long *cntp; /* interrupt counter */ +}; + +static struct sapic *ia64_sapics[16]; /* XXX make this resizable */ +static int ia64_sapic_count; +static struct mtx ia64_intrs_lock; +static struct ia64_intr *ia64_intrs[256]; + +static void ithds_init(void *dummy); + +static void +ithds_init(void *dummy) +{ + + mtx_init(&ia64_intrs_lock, "ithread table lock", MTX_SPIN); +} +SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL); + +void +ia64_add_sapic(struct sapic *sa) +{ + ia64_sapics[ia64_sapic_count++] = sa; +} + +static void +ia64_enable(int vector) +{ + int irq, i; + + irq = vector - IA64_HARDWARE_IRQ_BASE; + for (i = 0; i < ia64_sapic_count; i++) { + struct sapic *sa = ia64_sapics[i]; + if (irq >= sa->sa_base && irq <= sa->sa_limit) + sapic_enable(sa, irq - sa->sa_base, vector, + (irq < 16 + ? SAPIC_TRIGGER_EDGE + : SAPIC_TRIGGER_LEVEL), + (irq < 16 + ? SAPIC_POLARITY_HIGH + : SAPIC_POLARITY_LOW)); + } +} + +static void +ia64_send_eoi(int vector) +{ + int irq, i; + + irq = vector - IA64_HARDWARE_IRQ_BASE; + for (i = 0; i < ia64_sapic_count; i++) { + struct sapic *sa = ia64_sapics[i]; + if (irq >= sa->sa_base && irq <= sa->sa_limit) + sapic_eoi(sa, vector); + } +} + +int +ia64_setup_intr(const char *name, int irq, driver_intr_t handler, void *arg, + enum intr_type flags, void **cookiep, volatile long *cntp) +{ + struct ia64_intr *i; + int errcode; + int vector = irq + IA64_HARDWARE_IRQ_BASE; + + /* + * XXX - Can we have more than one device on a vector? If so, we have + * a race condition here that needs to be worked around similar to + * the fashion done in the i386 inthand_add() function. + */ + + /* First, check for an existing hash table entry for this vector. */ + mtx_lock_spin(&ia64_intrs_lock); + i = ia64_intrs[vector]; + mtx_unlock_spin(&ia64_intrs_lock); + + if (i == NULL) { + /* None was found, so create an entry. */ + i = malloc(sizeof(struct ia64_intr), M_DEVBUF, M_NOWAIT); + if (i == NULL) + return ENOMEM; + i->cntp = cntp; + errcode = ithread_create(&i->ithd, vector, 0, 0, + ia64_send_eoi, "intr:"); + if (errcode) { + free(i, M_DEVBUF); + return errcode; + } + + mtx_lock_spin(&ia64_intrs_lock); + ia64_intrs[vector] = i; + mtx_unlock_spin(&ia64_intrs_lock); + } + + /* Second, add this handler. */ + errcode = ithread_add_handler(i->ithd, name, handler, arg, + ithread_priority(flags), flags, cookiep); + if (errcode) + return errcode; + + ia64_enable(vector); + return 0; +} + +int +ia64_teardown_intr(void *cookie) +{ + + return (ithread_remove_handler(cookie)); +} + +void +ia64_dispatch_intr(void *frame, unsigned long vector) +{ + struct ia64_intr *i; + struct ithd *ithd; /* our interrupt thread */ + struct intrhand *ih; + int error; + + /* + * Find the interrupt thread for this vector. + */ + i = ia64_intrs[vector]; + if (i == NULL) + return; /* no ithread for this vector */ + + ithd = i->ithd; + KASSERT(ithd != NULL, ("interrupt vector without a thread")); + + /* + * As an optomization, if an ithread has no handlers, don't + * schedule it to run. + */ + if (TAILQ_EMPTY(&ithd->it_handlers)) + return; + + if (i->cntp) + atomic_add_long(i->cntp, 1); + + /* + * Handle a fast interrupt if there is no actual thread for this + * interrupt by calling the handler directly without Giant. Note + * that this means that any fast interrupt handler must be MP safe. + */ + ih = TAILQ_FIRST(&ithd->it_handlers); + if ((ih->ih_flags & IH_FAST) != 0) { + ih->ih_handler(ih->ih_argument); + ia64_send_eoi(vector); + return; + } + + error = ithread_schedule(ithd, 0); /* XXX:no preemption for now */ + KASSERT(error == 0, ("got an impossible stray interrupt")); +} + diff --git a/sys/ia64/ia64/nexus.c b/sys/ia64/ia64/nexus.c index 8ecd181..b0eac9b 100644 --- a/sys/ia64/ia64/nexus.c +++ b/sys/ia64/ia64/nexus.c @@ -59,6 +59,7 @@ #include <machine/resource.h> #include <isa/isavar.h> +#include <isa/isareg.h> #include <sys/rtprio.h> static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); @@ -163,7 +164,7 @@ nexus_probe(device_t dev) irq_rman.rm_start = 0; irq_rman.rm_type = RMAN_ARRAY; irq_rman.rm_descr = "Interrupt request lines"; - irq_rman.rm_end = 15; + irq_rman.rm_end = 63; if (rman_init(&irq_rman) || rman_manage_region(&irq_rman, irq_rman.rm_start, irq_rman.rm_end)) @@ -211,6 +212,12 @@ nexus_probe(device_t dev) static int nexus_attach(device_t dev) { + /* + * Mask the legacy PICs - we will use the I/O SAPIC for interrupt. + */ + outb(IO_ICU1+1, 0xff); + outb(IO_ICU2+1, 0xff); + bus_generic_attach(dev); return 0; } @@ -472,10 +479,8 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, if (error) return (error); -#if 0 - error = inthand_add(device_get_nameunit(child), irq->r_start, - ihand, arg, flags, cookiep); -#endif + error = ia64_setup_intr(device_get_nameunit(child), irq->r_start, + ihand, arg, flags, cookiep, 0); return (error); } diff --git a/sys/ia64/include/intr.h b/sys/ia64/include/intr.h index 4f00388..1519183 100644 --- a/sys/ia64/include/intr.h +++ b/sys/ia64/include/intr.h @@ -29,9 +29,30 @@ #ifndef _MACHINE_INTR_H_ #define _MACHINE_INTR_H_ -int alpha_setup_intr(int vector, driver_intr_t *intr, void *arg, - void **cookiep, volatile long *cntp); -int alpha_teardown_intr(void *cookie); -void alpha_dispatch_intr(void *frame, unsigned long vector); +/* + * Layout of the Processor Interrupt Block. + */ +struct ia64_interrupt_block +{ + u_int64_t ib_ipi[0x20000]; /* 1Mb of IPI interrupts */ + u_int8_t ib_reserved1[0xe0000]; + u_int8_t ib_inta; /* Generate INTA cycle */ + u_int8_t ib_reserved2[7]; + u_int8_t ib_xtp; /* XTP cycle */ + u_int8_t ib_reserved3[7]; + u_int8_t ib_reserved4[0x1fff0]; +}; + +#define IA64_INTERRUPT_BLOCK \ + (struct ia64_interrupt_block *)IA64_PHYS_TO_RR6(0xfee00000) + +struct sapic; + +void ia64_add_sapic(struct sapic *sa); +int ia64_setup_intr(const char *name, int irq, driver_intr_t handler, + void *arg, enum intr_type flags, void **cookiep, + volatile long *cntp); +int ia64_teardown_intr(void *cookie); +void ia64_dispatch_intr(void *frame, unsigned long vector); #endif /* !_MACHINE_INTR_H_ */ diff --git a/sys/ia64/include/sapicreg.h b/sys/ia64/include/sapicreg.h new file mode 100644 index 0000000..8f7dfbd --- /dev/null +++ b/sys/ia64/include/sapicreg.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2001 Doug Rabson + * All rights reserved. + * + * 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 AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_SAPICREG_H_ +#define _MACHINE_SAPICREG_H_ + +/* + * Offsets from the SAPIC base in memory. Most registers are accessed + * by indexing using the SAPIC_IO_SELECT register. + */ +#define SAPIC_IO_SELECT 0x00 +#define SAPIC_IO_WINDOW 0x10 +#define SAPIC_APIC_EOI 0x40 + +/* + * Indexed registers. + */ +#define SAPIC_ID 0x00 +#define SAPIC_VERSION 0x01 +#define SAPIC_ARBITRATION_ID 0x02 +#define SAPIC_RTE_BASE 0x10 + +#endif /* ! _MACHINE_SAPICREG_H_ */ diff --git a/sys/ia64/include/sapicvar.h b/sys/ia64/include/sapicvar.h new file mode 100644 index 0000000..8fbdf90 --- /dev/null +++ b/sys/ia64/include/sapicvar.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2001 Doug Rabson + * All rights reserved. + * + * 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 AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_SAPICVAR_H_ +#define _MACHINE_SAPICVAR_H_ + +struct sapic { + int sa_id; /* I/O SAPIC Id */ + int sa_base; /* ACPI vector base */ + int sa_limit; /* last ACPI vector handled here */ + vm_offset_t sa_registers; /* virtual address of sapic */ +}; + +#define SAPIC_TRIGGER_EDGE 0 +#define SAPIC_TRIGGER_LEVEL 1 + +#define SAPIC_POLARITY_HIGH 0 +#define SAPIC_POLARITY_LOW 1 + +struct sapic *sapic_create(int id, int base, u_int64_t address); +void sapic_enable(struct sapic *sa, int input, int vector, + int trigger_mode, int polarity); +void sapic_eoi(struct sapic *sa, int vector); + +#endif /* ! _MACHINE_SAPICVAR_H_ */ |