summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/ia64/acpica/madt.c48
-rw-r--r--sys/ia64/ia64/interrupt.c192
-rw-r--r--sys/ia64/ia64/nexus.c15
-rw-r--r--sys/ia64/include/intr.h29
-rw-r--r--sys/ia64/include/sapicreg.h48
-rw-r--r--sys/ia64/include/sapicvar.h50
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_ */
OpenPOWER on IntegriCloud