Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 17 Mar 2010 00:37:16 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r205234 - in head/sys/ia64: ia64 include
Message-ID:  <201003170037.o2H0bGc5043447@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Wed Mar 17 00:37:15 2010
New Revision: 205234
URL: http://svn.freebsd.org/changeset/base/205234

Log:
  Revamp the interrupt code based on the previous commit:
  o   Introduce XIV, eXternal Interrupt Vector, to differentiate from
      the interrupts vectors that are offsets in the IVT (Interrupt
      Vector Table). There's a vector for external interrupts, which
      are based on the XIVs.
  
  o   Keep track of allocated and reserved XIVs so that we can assign
      XIVs without hardcoding anything. When XIVs are allocated, an
      interrupt handler and a class is specified for the XIV. Classes
      are:
      1.  architecture-defined: XIV 15 is returned when no external
  	interrupt are pending,
      2.  platform-defined: SAL reports which XIV is used to wakeup
  	an AP (typically 0xFF, but it's 0x12 for the Altix 350).
      3.  inter-processor interrupts: allocated for SMP support and
  	non-redirectable.
      4.  device interrupts (i.e. IRQs): allocated when devices are
  	discovered and are redirectable.
  
  o   Rewrite the central interrupt handler to call the per-XIV
      interrupt handler and rename it to ia64_handle_intr(). Move
      the per-XIV handler implementation to the file where we have
      the XIV allocation/reservation. Clock interrupt handling is
      moved to clock.c. IPI handling is moved to mp_machdep.c.
  
  o   Drop support for the Intel 8259A because it was broken. When
      XIV 0 is received, the CPU should initiate an INTA cycle to
      obtain the interrupt vector of the 8259-based interrupt. In
      these cases the interrupt controller we should be talking to
      WRT to masking on signalling EOI is the 8259 and not the I/O
      SAPIC. This requires adriver for the Intel 8259A which isn't
      available for ia64. Thus stop pretending to support ExtINTs
      and instead panic() so that if we come across hardware that
      has an Intel 8259A, so have something real to work with.
  
  o   With XIVs for IPIs dynamically allocatedi and also based on
      priority, define the IPI_* symbols as variables rather than
      constants. The variable holds the XIV allocated for the IPI.
  
  o   IPI_STOP_HARD delivers a NMI if possible. Otherwise the XIV
      assigned to IPI_STOP is delivered.

Modified:
  head/sys/ia64/ia64/clock.c
  head/sys/ia64/ia64/exception.S
  head/sys/ia64/ia64/highfp.c
  head/sys/ia64/ia64/interrupt.c
  head/sys/ia64/ia64/locore.S
  head/sys/ia64/ia64/machdep.c
  head/sys/ia64/ia64/mp_machdep.c
  head/sys/ia64/ia64/nexus.c
  head/sys/ia64/ia64/sal.c
  head/sys/ia64/include/clock.h
  head/sys/ia64/include/intr.h
  head/sys/ia64/include/intrcnt.h
  head/sys/ia64/include/smp.h

Modified: head/sys/ia64/ia64/clock.c
==============================================================================
--- head/sys/ia64/ia64/clock.c	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/clock.c	Wed Mar 17 00:37:15 2010	(r205234)
@@ -29,19 +29,41 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/priority.h>
 #include <sys/queue.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
-#include <sys/bus.h>
 #include <sys/timetc.h>
 #include <sys/pcpu.h>
 
-#include <machine/clock.h>
 #include <machine/cpu.h>
 #include <machine/efi.h>
+#include <machine/intr.h>
+#include <machine/intrcnt.h>
 #include <machine/md_var.h>
 
-uint64_t ia64_clock_reload;
+SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
+
+static int adjust_edges = 0;
+SYSCTL_INT(_debug_clock, OID_AUTO, adjust_edges, CTLFLAG_RD,
+    &adjust_edges, 0, "Number of times ITC got more than 12.5% behind");
+
+static int adjust_excess = 0;
+SYSCTL_INT(_debug_clock, OID_AUTO, adjust_excess, CTLFLAG_RD,
+    &adjust_excess, 0, "Total number of ignored ITC interrupts");
+
+static int adjust_lost = 0;
+SYSCTL_INT(_debug_clock, OID_AUTO, adjust_lost, CTLFLAG_RD,
+    &adjust_lost, 0, "Total number of lost ITC interrupts");
+
+static int adjust_ticks = 0;
+SYSCTL_INT(_debug_clock, OID_AUTO, adjust_ticks, CTLFLAG_RD,
+    &adjust_ticks, 0, "Total number of ITC interrupts with adjustment");
+
+static u_int ia64_clock_xiv;
+static uint64_t ia64_clock_reload;
 
 #ifndef SMP
 static timecounter_get_t ia64_get_timecount;
@@ -54,13 +76,68 @@ static struct timecounter ia64_timecount
 	"ITC"			/* name */
 };
 
-static unsigned
+static u_int
 ia64_get_timecount(struct timecounter* tc)
 {
 	return ia64_get_itc();
 }
 #endif
 
+static u_int
+ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf)
+{
+	uint64_t adj, clk, itc;
+	int64_t delta;
+	int count;
+
+	ia64_set_eoi(0);
+
+	PCPU_INC(md.stats.pcs_nclks);
+	intrcnt[INTRCNT_CLOCK]++;
+
+	ia64_srlz_d();
+
+	itc = ia64_get_itc();
+
+	adj = PCPU_GET(md.clockadj);
+	clk = PCPU_GET(md.clock);
+
+	delta = itc - clk;
+	count = 0;
+	while (delta >= ia64_clock_reload) {
+		/* Only the BSP runs the real clock */
+		if (PCPU_GET(cpuid) == 0)
+			hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
+		else
+			hardclock_cpu(TRAPF_USERMODE(tf));
+		if (profprocs != 0)
+			profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
+		statclock(TRAPF_USERMODE(tf));
+		delta -= ia64_clock_reload;
+		clk += ia64_clock_reload;
+		if (adj != 0)
+			adjust_ticks++;
+		count++;
+	}
+	ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
+	if (count > 0) {
+		adjust_lost += count - 1;
+		if (delta > (ia64_clock_reload >> 3)) {
+			if (adj == 0)
+				adjust_edges++;
+			adj = ia64_clock_reload >> 4;
+		} else
+			adj = 0;
+	} else {
+		adj = 0;
+		adjust_excess++;
+	}
+	PCPU_SET(md.clock, clk);
+	PCPU_SET(md.clockadj, adj);
+	ia64_srlz_d();
+	return (0);
+}
+
 void
 pcpu_initclock(void)
 {
@@ -68,7 +145,7 @@ pcpu_initclock(void)
 	PCPU_SET(md.clockadj, 0);
 	PCPU_SET(md.clock, ia64_get_itc());
 	ia64_set_itm(PCPU_GET(md.clock) + ia64_clock_reload);
-	ia64_set_itv(CLOCK_VECTOR);	/* highest priority class */
+	ia64_set_itv(ia64_clock_xiv);
 	ia64_srlz_d();
 }
 
@@ -81,6 +158,11 @@ cpu_initclocks()
 {
 	u_long itc_freq;
 
+	ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IRQ,
+	    ia64_ih_clock);
+	if (ia64_clock_xiv == 0)
+		panic("No XIV for clock interrupts");
+
 	itc_freq = (u_long)ia64_itc_freq() * 1000000ul;
 
 	stathz = hz;

Modified: head/sys/ia64/ia64/exception.S
==============================================================================
--- head/sys/ia64/ia64/exception.S	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/exception.S	Wed Mar 17 00:37:15 2010	(r205234)
@@ -1303,7 +1303,7 @@ IVT_END(Break_Instruction)
 
 IVT_ENTRY(External_Interrupt, 0x3000)
 {	.mib
-	mov		r17=cr.ivr	// Put the vector in the trap frame.
+	mov		r17=cr.ivr	// Put the XIV in the trapframe.
 	mov		r16=ip
 	br.sptk		exception_save
 	;;
@@ -1317,7 +1317,7 @@ IVT_ENTRY(External_Interrupt, 0x3000)
 {	.mib
 	add		out0=16,sp
 	nop		0
-	br.call.sptk	rp=interrupt
+	br.call.sptk	rp=ia64_handle_intr
 	;;
 }
 {	.mib

Modified: head/sys/ia64/ia64/highfp.c
==============================================================================
--- head/sys/ia64/ia64/highfp.c	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/highfp.c	Wed Mar 17 00:37:15 2010	(r205234)
@@ -53,7 +53,7 @@ ia64_highfp_ipi(struct pcpu *cpu)
 {
 	int error;
 
-	ipi_send(cpu, IPI_HIGH_FP);
+	ipi_send(cpu, ia64_ipi_highfp);
 	error = msleep_spin(&cpu->pc_fpcurthread, &ia64_highfp_mtx,
 	    "High FP", 0);
 	return (error);

Modified: head/sys/ia64/ia64/interrupt.c
==============================================================================
--- head/sys/ia64/ia64/interrupt.c	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/interrupt.c	Wed Mar 17 00:37:15 2010	(r205234)
@@ -43,6 +43,7 @@
 #include <sys/proc.h>
 #include <sys/vmmeter.h>
 #include <sys/bus.h>
+#include <sys/interrupt.h>
 #include <sys/malloc.h>
 #include <sys/ktr.h>
 #include <sys/lock.h>
@@ -52,46 +53,20 @@
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
 
-#include <machine/clock.h>
 #include <machine/cpu.h>
 #include <machine/fpu.h>
 #include <machine/frame.h>
 #include <machine/intr.h>
+#include <machine/intrcnt.h>
 #include <machine/md_var.h>
 #include <machine/pcb.h>
 #include <machine/reg.h>
 #include <machine/smp.h>
 
-#ifdef EVCNT_COUNTERS
-struct evcnt clock_intr_evcnt;	/* event counter for clock intrs. */
-#else
-#include <sys/interrupt.h>
-#include <machine/intrcnt.h>
-#endif
-
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif
 
-SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
-
-static int adjust_edges = 0;
-SYSCTL_INT(_debug_clock, OID_AUTO, adjust_edges, CTLFLAG_RD,
-    &adjust_edges, 0, "Number of times ITC got more than 12.5% behind");
-
-static int adjust_excess = 0;
-SYSCTL_INT(_debug_clock, OID_AUTO, adjust_excess, CTLFLAG_RD,
-    &adjust_excess, 0, "Total number of ignored ITC interrupts");
-
-static int adjust_lost = 0;
-SYSCTL_INT(_debug_clock, OID_AUTO, adjust_lost, CTLFLAG_RD,
-    &adjust_lost, 0, "Total number of lost ITC interrupts");
-
-static int adjust_ticks = 0;
-SYSCTL_INT(_debug_clock, OID_AUTO, adjust_ticks, CTLFLAG_RD,
-    &adjust_ticks, 0, "Total number of ITC interrupts with adjustment");
-
-
 struct ia64_intr {
 	struct intr_event *event;	/* interrupt event */
 	volatile long *cntp;		/* interrupt counter */
@@ -99,190 +74,120 @@ struct ia64_intr {
 	u_int	irq;
 };
 
-static struct ia64_intr *ia64_intrs[256];
+ia64_ihtype *ia64_handler[IA64_NXIVS];
 
+static enum ia64_xiv_use ia64_xiv[IA64_NXIVS];
+static struct ia64_intr *ia64_intrs[IA64_NXIVS];
 
-static void ia64_dispatch_intr(void *, u_int);
+static ia64_ihtype ia64_ih_invalid;
+static ia64_ihtype ia64_ih_irq;
 
 void
-interrupt(struct trapframe *tf)
+ia64_xiv_init(void)
 {
-	struct thread *td;
-	uint64_t adj, clk, itc;
-	int64_t delta;
-	u_int vector;
-	int count;
-	uint8_t inta;
+	u_int xiv;
 
-	ia64_set_fpsr(IA64_FPSR_DEFAULT);
+	for (xiv = 0; xiv < IA64_NXIVS; xiv++) {
+		ia64_handler[xiv] = ia64_ih_invalid;
+		ia64_xiv[xiv] = IA64_XIV_FREE;
+		ia64_intrs[xiv] = NULL;
+	}
+	(void)ia64_xiv_reserve(15, IA64_XIV_ARCH, NULL);
+}
 
-	td = curthread;
+int
+ia64_xiv_free(u_int xiv, enum ia64_xiv_use what)
+{
 
-	PCPU_INC(cnt.v_intr);
+	if (xiv >= IA64_NXIVS)
+		return (EINVAL);
+	if (what == IA64_XIV_FREE || what == IA64_XIV_ARCH)
+		return (EINVAL);
+	if (ia64_xiv[xiv] != what)
+		return (ENXIO);
+	ia64_xiv[xiv] = IA64_XIV_FREE;
+	ia64_handler[xiv] = ia64_ih_invalid;
+	return (0);
+}
 
-	vector = tf->tf_special.ifa;
+int
+ia64_xiv_reserve(u_int xiv, enum ia64_xiv_use what, ia64_ihtype ih)
+{
 
- next:
-	/*
-	 * Handle ExtINT interrupts by generating an INTA cycle to
-	 * read the vector.
-	 */
-	if (vector == 0) {
-		PCPU_INC(md.stats.pcs_nextints);
-		inta = ia64_ld1(&ia64_pib->ib_inta);
-		if (inta == 15) {
-			PCPU_INC(md.stats.pcs_nstrays);
-			__asm __volatile("mov cr.eoi = r0;; srlz.d");
-			goto stray;
-		}
-		vector = (int)inta;
-	} else if (vector == 15) {
-		PCPU_INC(md.stats.pcs_nstrays);
-		goto stray;
-	}
+	if (xiv >= IA64_NXIVS)
+		return (EINVAL);
+	if (what == IA64_XIV_FREE)
+		return (EINVAL);
+	if (ia64_xiv[xiv] != IA64_XIV_FREE)
+		return (EBUSY);
+	ia64_xiv[xiv] = what;
+	ia64_handler[xiv] = (ih == NULL) ? ia64_ih_invalid: ih;
+	if (1 || bootverbose)
+		printf("XIV %u: use=%u, IH=%p\n", xiv, what, ih);
+	return (0);
+}
 
-	if (vector == CLOCK_VECTOR) {/* clock interrupt */
-		/* CTR0(KTR_INTR, "clock interrupt"); */
+u_int
+ia64_xiv_alloc(u_int prio, enum ia64_xiv_use what, ia64_ihtype ih)
+{
+	u_int hwprio;
+	u_int xiv0, xiv;
 
-		itc = ia64_get_itc();
+	hwprio = prio >> 2;
+	if (hwprio > IA64_MAX_HWPRIO)
+		hwprio = IA64_MAX_HWPRIO;
 
-		PCPU_INC(md.stats.pcs_nclks);
-#ifdef EVCNT_COUNTERS
-		clock_intr_evcnt.ev_count++;
-#else
-		intrcnt[INTRCNT_CLOCK]++;
-#endif
+	xiv0 = IA64_NXIVS - (hwprio + 1) * 16;
 
-		critical_enter();
+	KASSERT(xiv0 > IA64_MIN_XIV, ("%s: min XIV", __func__));
+	KASSERT(xiv0 < IA64_NXIVS, ("%s: max XIV", __func__));
 
-		adj = PCPU_GET(md.clockadj);
-		clk = PCPU_GET(md.clock);
-		delta = itc - clk;
-		count = 0;
-		while (delta >= ia64_clock_reload) {
-			/* Only the BSP runs the real clock */
-			if (PCPU_GET(cpuid) == 0)
-				hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
-			else
-				hardclock_cpu(TRAPF_USERMODE(tf));
-			if (profprocs != 0)
-				profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
-			statclock(TRAPF_USERMODE(tf));
-			delta -= ia64_clock_reload;
-			clk += ia64_clock_reload;
-			if (adj != 0)
-				adjust_ticks++;
-			count++;
-		}
-		ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
-		if (count > 0) {
-			adjust_lost += count - 1;
-			if (delta > (ia64_clock_reload >> 3)) {
-				if (adj == 0)
-					adjust_edges++;
-				adj = ia64_clock_reload >> 4;
-			} else
-				adj = 0;
-		} else {
-			adj = 0;
-			adjust_excess++;
-		}
-		PCPU_SET(md.clock, clk);
-		PCPU_SET(md.clockadj, adj);
-		critical_exit();
-		ia64_srlz_d();
+	xiv = xiv0;
+	while (xiv < IA64_NXIVS && ia64_xiv_reserve(xiv, what, ih))
+		xiv++;
 
-#ifdef SMP
-	} else if (vector == ipi_vector[IPI_AST]) {
-		PCPU_INC(md.stats.pcs_nasts);
-		CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
-	} else if (vector == ipi_vector[IPI_HIGH_FP]) {
-		PCPU_INC(md.stats.pcs_nhighfps);
-		ia64_highfp_save_ipi();
-	} else if (vector == ipi_vector[IPI_RENDEZVOUS]) {
-		PCPU_INC(md.stats.pcs_nrdvs);
-		CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
-		enable_intr();
-		smp_rendezvous_action();
-		disable_intr();
-	} else if (vector == ipi_vector[IPI_STOP]) {
-		PCPU_INC(md.stats.pcs_nstops);
-		cpumask_t mybit = PCPU_GET(cpumask);
-
-		/* Make sure IPI_STOP_HARD is mapped to IPI_STOP. */
-		KASSERT(IPI_STOP == IPI_STOP_HARD,
-		    ("%s: IPI_STOP_HARD not handled.", __func__));
-
-		savectx(PCPU_PTR(md.pcb));
-		atomic_set_int(&stopped_cpus, mybit);
-		while ((started_cpus & mybit) == 0)
-			cpu_spinwait();
-		atomic_clear_int(&started_cpus, mybit);
-		atomic_clear_int(&stopped_cpus, mybit);
-	} else if (vector == ipi_vector[IPI_PREEMPT]) {
-		PCPU_INC(md.stats.pcs_npreempts);
-		CTR1(KTR_SMP, "IPI_PREEMPT, cpuid=%d", PCPU_GET(cpuid));
-		__asm __volatile("mov cr.eoi = r0;; srlz.d");
-		enable_intr();
-		sched_preempt(curthread);
-		disable_intr();
-		goto stray;
-#endif
-	} else {
-		PCPU_INC(md.stats.pcs_nhwints);
-		atomic_add_int(&td->td_intr_nesting_level, 1);
-		ia64_dispatch_intr(tf, vector);
-		atomic_subtract_int(&td->td_intr_nesting_level, 1);
-	}
+	if (xiv < IA64_NXIVS)
+		return (xiv);
 
-	__asm __volatile("mov cr.eoi = r0;; srlz.d");
-	vector = ia64_get_ivr();
-	if (vector != 15)
-		goto next;
+	xiv = xiv0;
+	while (xiv >= IA64_MIN_XIV && ia64_xiv_reserve(xiv, what, ih))
+		xiv--;
 
-stray:
-	if (TRAPF_USERMODE(tf)) {
-		enable_intr();
-		userret(td, tf);
-		mtx_assert(&Giant, MA_NOTOWNED);
-		do_ast(tf);
-	}
+	return ((xiv >= IA64_MIN_XIV) ? xiv : 0);
 }
 
-
 static void
 ia64_intr_eoi(void *arg)
 {
-	u_int vector = (uintptr_t)arg;
+	u_int xiv = (uintptr_t)arg;
 	struct ia64_intr *i;
 
-	i = ia64_intrs[vector];
-	if (i != NULL)
-		sapic_eoi(i->sapic, vector);
+	i = ia64_intrs[xiv];
+	KASSERT(i != NULL, ("%s", __func__));
+	sapic_eoi(i->sapic, xiv);
 }
 
 static void
 ia64_intr_mask(void *arg)
 {
-	u_int vector = (uintptr_t)arg;
+	u_int xiv = (uintptr_t)arg;
 	struct ia64_intr *i;
 
-	i = ia64_intrs[vector];
-	if (i != NULL) {
-		sapic_mask(i->sapic, i->irq);
-		sapic_eoi(i->sapic, vector);
-	}
+	i = ia64_intrs[xiv];
+	KASSERT(i != NULL, ("%s", __func__));
+	sapic_mask(i->sapic, i->irq);
+	sapic_eoi(i->sapic, xiv);
 }
 
 static void
 ia64_intr_unmask(void *arg)
 {
-	u_int vector = (uintptr_t)arg;
+	u_int xiv = (uintptr_t)arg;
 	struct ia64_intr *i;
 
-	i = ia64_intrs[vector];
-	if (i != NULL)
-		sapic_unmask(i->sapic, i->irq);
+	i = ia64_intrs[xiv];
+	KASSERT(i != NULL, ("%s", __func__));
+	sapic_unmask(i->sapic, i->irq);
 }
 
 int
@@ -292,7 +197,7 @@ ia64_setup_intr(const char *name, int ir
 	struct ia64_intr *i;
 	struct sapic *sa;
 	char *intrname;
-	u_int prio, vector;
+	u_int prio, xiv;
 	int error;
 
 	prio = intr_priority(flags);
@@ -301,37 +206,41 @@ ia64_setup_intr(const char *name, int ir
 
 	/* XXX lock */
 
-	/* Get the I/O SAPIC and vector that corresponds to the IRQ. */
-	sa = sapic_lookup(irq, &vector);
+	/* Get the I/O SAPIC and XIV that corresponds to the IRQ. */
+	sa = sapic_lookup(irq, &xiv);
 	if (sa == NULL) {
 		/* XXX unlock */
 		return (EINVAL);
 	}
 
-	if (vector == 0) {
+	if (xiv == 0) {
 		/* XXX unlock */
 		i = malloc(sizeof(struct ia64_intr), M_DEVBUF,
 		    M_ZERO | M_WAITOK);
 		/* XXX lock */
-		sa = sapic_lookup(irq, &vector);
+		sa = sapic_lookup(irq, &xiv);
 		KASSERT(sa != NULL, ("sapic_lookup"));
-		if (vector != 0)
+		if (xiv != 0)
 			free(i, M_DEVBUF);
 	}
 
 	/*
-	 * If the IRQ has no vector assigned to it yet, assign one based
+	 * If the IRQ has no XIV assigned to it yet, assign one based
 	 * on the priority.
 	 */
-	if (vector == 0) {
-		vector = (256 - 64) - (prio << 1);
-		while (vector < 256 && ia64_intrs[vector] != NULL)
-			vector++;
+	if (xiv == 0) {
+		xiv = ia64_xiv_alloc(prio, IA64_XIV_IRQ, ia64_ih_irq);
+		if (xiv == 0) {
+			/* XXX unlock */
+			free(i, M_DEVBUF);
+			return (ENOSPC);
+		}
 
-		error = intr_event_create(&i->event, (void *)(uintptr_t)vector,
+		error = intr_event_create(&i->event, (void *)(uintptr_t)xiv,
 		    0, irq, ia64_intr_mask, ia64_intr_unmask, ia64_intr_eoi,
 		    NULL, "irq%u:", irq);
 		if (error) {
+			ia64_xiv_free(xiv, IA64_XIV_IRQ);
 			/* XXX unlock */
 			free(i, M_DEVBUF);
 			return (error);
@@ -339,25 +248,25 @@ ia64_setup_intr(const char *name, int ir
 
 		i->sapic = sa;
 		i->irq = irq;
-		i->cntp = intrcnt + irq + INTRCNT_ISA_IRQ;
-		ia64_intrs[vector] = i;
-		sapic_enable(sa, irq, vector);
+		i->cntp = intrcnt + xiv;
+		ia64_intrs[xiv] = i;
 
 		/* XXX unlock */
 
+		sapic_enable(sa, irq, xiv);
+
 		if (name != NULL && *name != '\0') {
 			/* XXX needs abstraction. Too error prone. */
-			intrname = intrnames +
-			    (irq + INTRCNT_ISA_IRQ) * INTRNAME_LEN;
+			intrname = intrnames + xiv * INTRNAME_LEN;
 			memset(intrname, ' ', INTRNAME_LEN - 1);
 			bcopy(name, intrname, strlen(name));
 		}
 	} else {
-		i = ia64_intrs[vector];
+		i = ia64_intrs[xiv];
 		/* XXX unlock */
 	}
 
-	KASSERT(i != NULL, ("vector mapping bug"));
+	KASSERT(i != NULL, ("XIV mapping bug"));
 
 	error = intr_event_add_handler(i->event, name, filter, handler, arg,
 	    prio, flags, cookiep);
@@ -371,62 +280,114 @@ ia64_teardown_intr(void *cookie)
 	return (intr_event_remove_handler(cookie));
 }
 
-static void
-ia64_dispatch_intr(void *frame, u_int vector)
+/*
+ * Interrupt handlers.
+ */
+
+void
+ia64_handle_intr(struct trapframe *tf)
+{
+	struct thread *td;
+	u_int rfi, xiv;
+
+	td = curthread;
+	ia64_set_fpsr(IA64_FPSR_DEFAULT);
+	PCPU_INC(cnt.v_intr);
+
+	xiv = tf->tf_special.ifa;
+	if (xiv == 15) {
+		PCPU_INC(md.stats.pcs_nstrays);
+		goto out;
+	}
+
+	while (xiv != 15) {
+		CTR1(KTR_INTR, "INTR: XIV=%u", xiv);
+		critical_enter();
+		rfi = (ia64_handler[xiv])(td, xiv, tf);
+		if (rfi) {
+			critical_exit();
+			return;
+		}
+		xiv = ia64_get_ivr();
+		critical_exit();
+		ia64_srlz_d();
+	}
+
+ out:
+	if (TRAPF_USERMODE(tf)) {
+		while (td->td_flags & (TDF_ASTPENDING|TDF_NEEDRESCHED)) {
+			enable_intr();
+			ast(tf);
+			disable_intr();
+		}
+	}
+}
+
+static u_int
+ia64_ih_invalid(struct thread *td, u_int xiv, struct trapframe *tf)
+{
+
+	ia64_set_eoi(0);
+	ia64_srlz_d();
+	panic("invalid XIV: %u", xiv);
+	return (1);
+}
+
+static u_int
+ia64_ih_irq(struct thread *td, u_int xiv, struct trapframe *tf)
 {
 	struct ia64_intr *i;
 	struct intr_event *ie;			/* our interrupt event */
 
-	/*
-	 * Find the interrupt thread for this vector.
-	 */
-	i = ia64_intrs[vector];
-	KASSERT(i != NULL, ("%s: unassigned vector", __func__));
+	PCPU_INC(md.stats.pcs_nhwints);
+
+	/* Find the interrupt thread for this XIV. */
+	i = ia64_intrs[xiv];
+	KASSERT(i != NULL, ("%s: unassigned XIV", __func__));
 
 	(*i->cntp)++;
 
 	ie = i->event;
 	KASSERT(ie != NULL, ("%s: interrupt without event", __func__));
 
-	if (intr_event_handle(ie, frame) != 0) {
-		/*
-		 * XXX: The pre-INTR_FILTER code didn't mask stray
-		 * interrupts.
-		 */
-		ia64_intr_mask((void *)(uintptr_t)vector);
+	if (intr_event_handle(ie, tf) != 0) {
+		ia64_intr_mask((void *)(uintptr_t)xiv);
 		log(LOG_ERR, "stray irq%u\n", i->irq);
 	}
+	ia64_set_eoi(0);
+	ia64_srlz_d();
+	return (0);
 }
 
 #ifdef DDB
 
 static void
-db_print_vector(u_int vector, int always)
+db_print_xiv(u_int xiv, int always)
 {
 	struct ia64_intr *i;
 
-	i = ia64_intrs[vector];
+	i = ia64_intrs[xiv];
 	if (i != NULL) {
-		db_printf("vector %u (%p): ", vector, i);
+		db_printf("XIV %u (%p): ", xiv, i);
 		sapic_print(i->sapic, i->irq);
 	} else if (always)
-		db_printf("vector %u: unassigned\n", vector);
+		db_printf("XIV %u: unassigned\n", xiv);
 }
 
-DB_SHOW_COMMAND(vector, db_show_vector)
+DB_SHOW_COMMAND(xiv, db_show_xiv)
 {
-	u_int vector;
+	u_int xiv;
 
 	if (have_addr) {
-		vector = ((addr >> 4) % 16) * 10 + (addr % 16);
-		if (vector >= 256)
-			db_printf("error: vector %u not in range [0..255]\n",
-			    vector);
+		xiv = ((addr >> 4) % 16) * 10 + (addr % 16);
+		if (xiv >= IA64_NXIVS)
+			db_printf("error: XIV %u not in range [0..%u]\n",
+			    xiv, IA64_NXIVS - 1);
 		else
-			db_print_vector(vector, 1);
+			db_print_xiv(xiv, 1);
 	} else {
-		for (vector = 0; vector < 256; vector++)
-			db_print_vector(vector, 0);
+		for (xiv = 0; xiv < IA64_NXIVS; xiv++)
+			db_print_xiv(xiv, 0);
 	}
 }
 

Modified: head/sys/ia64/ia64/locore.S
==============================================================================
--- head/sys/ia64/ia64/locore.S	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/locore.S	Wed Mar 17 00:37:15 2010	(r205234)
@@ -26,16 +26,13 @@
  * $FreeBSD$
  */
 
+#include <sys/syscall.h>
 #include <machine/asm.h>
 #include <machine/ia64_cpu.h>
+#include <machine/intrcnt.h>
 #include <machine/pte.h>
-#include <sys/syscall.h>
-#include <assym.s>
-
-#ifndef EVCNT_COUNTERS
-#define _LOCORE
 #include <machine/intrcnt.h>
-#endif
+#include <assym.s>
 
 	.section .data.proc0,"aw"
 	.global	kstack
@@ -310,7 +307,7 @@ EXPORT(intrnames)
 	.ascii "clock"
 	.fill INTRNAME_LEN - 5 - 1, 1, ' '
 	.byte 0
-intr_n = 0
+intr_n = 1
 .rept INTRCNT_COUNT - 1
 	.ascii "#"
 	.byte intr_n / 100 + '0'

Modified: head/sys/ia64/ia64/machdep.c
==============================================================================
--- head/sys/ia64/ia64/machdep.c	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/machdep.c	Wed Mar 17 00:37:15 2010	(r205234)
@@ -371,7 +371,7 @@ cpu_startup(void *dummy)
 		SYSCTL_ADD_ULONG(&pc->pc_md.sysctl_ctx,
 		    SYSCTL_CHILDREN(pc->pc_md.sysctl_tree), OID_AUTO,
 		    "nstrays", CTLFLAG_RD, &pcs->pcs_nstrays,
-		    "Number of stray vectors");
+		    "Number of stray interrupts");
 	}
 }
 SYSINIT(cpu_startup, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
@@ -781,6 +781,7 @@ ia64_init(void)
 	 */
 	map_pal_code();
 	efi_boot_minimal(bootinfo.bi_systab);
+	ia64_xiv_init();
 	ia64_sal_init();
 	calculate_frequencies();
 

Modified: head/sys/ia64/ia64/mp_machdep.c
==============================================================================
--- head/sys/ia64/ia64/mp_machdep.c	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/mp_machdep.c	Wed Mar 17 00:37:15 2010	(r205234)
@@ -46,11 +46,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 #include <sys/uuid.h>
 
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <vm/vm_extern.h>
-#include <vm/vm_kern.h>
-
 #include <machine/atomic.h>
 #include <machine/cpu.h>
 #include <machine/fpu.h>
@@ -59,10 +54,13 @@ __FBSDID("$FreeBSD$");
 #include <machine/md_var.h>
 #include <machine/pal.h>
 #include <machine/pcb.h>
-#include <machine/pmap.h>
 #include <machine/sal.h>
 #include <machine/smp.h>
-#include <i386/include/specialreg.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
 
 MALLOC_DEFINE(M_SMP, "SMP", "SMP related allocations");
 
@@ -81,7 +79,78 @@ volatile int ap_delay;
 volatile int ap_awake;
 volatile int ap_spin;
 
-static void cpu_mp_unleash(void *);
+int ia64_ipi_ast;
+int ia64_ipi_highfp;
+int ia64_ipi_nmi;
+int ia64_ipi_preempt;
+int ia64_ipi_rndzvs;
+int ia64_ipi_stop;
+
+static u_int
+ia64_ih_ast(struct thread *td, u_int xiv, struct trapframe *tf)
+{
+
+	ia64_set_eoi(0);
+	PCPU_INC(md.stats.pcs_nasts);
+	CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
+	ia64_srlz_d();
+	return (0);
+}
+
+static u_int
+ia64_ih_highfp(struct thread *td, u_int xiv, struct trapframe *tf)
+{
+
+	ia64_set_eoi(0);
+	PCPU_INC(md.stats.pcs_nhighfps);
+	ia64_highfp_save_ipi();
+	ia64_srlz_d();
+	return (0);
+}
+
+static u_int
+ia64_ih_preempt(struct thread *td, u_int xiv, struct trapframe *tf)
+{
+
+	ia64_set_eoi(0);
+	PCPU_INC(md.stats.pcs_npreempts);
+	CTR1(KTR_SMP, "IPI_PREEMPT, cpuid=%d", PCPU_GET(cpuid));
+	sched_preempt(curthread);
+	ia64_srlz_d();
+	return (0);
+}
+
+static u_int
+ia64_ih_rndzvs(struct thread *td, u_int xiv, struct trapframe *tf)
+{
+
+	ia64_set_eoi(0);
+	PCPU_INC(md.stats.pcs_nrdvs);
+	CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
+	smp_rendezvous_action();
+	ia64_srlz_d();
+	return (0);
+}
+
+static u_int
+ia64_ih_stop(struct thread *td, u_int xiv, struct trapframe *tf)
+{
+	cpumask_t mybit;
+
+	ia64_set_eoi(0);
+	PCPU_INC(md.stats.pcs_nstops);
+	mybit = PCPU_GET(cpumask);
+	ia64_srlz_d();
+
+	savectx(PCPU_PTR(md.pcb));
+
+	atomic_set_int(&stopped_cpus, mybit);
+	while ((started_cpus & mybit) == 0)
+		cpu_spinwait();
+	atomic_clear_int(&started_cpus, mybit);
+	atomic_clear_int(&stopped_cpus, mybit);
+	return (0);
+}
 
 struct cpu_group *
 cpu_topo(void)
@@ -116,7 +185,6 @@ void
 ia64_ap_startup(void)
 {
 	uint64_t vhpt;
-	int vector;
 
 	pcpup = ap_pcpu;
 	ia64_set_k4((intptr_t)pcpup);
@@ -148,18 +216,6 @@ ia64_ap_startup(void)
 
 	CTR1(KTR_SMP, "SMP: cpu%d launched", PCPU_GET(cpuid));
 
-	/* Acknowledge and EOI all interrupts. */
-	vector = ia64_get_ivr();
-	while (vector != 15) {
-		ia64_srlz_d();
-		if (vector == 0)
-			vector = (int)ia64_ld1(&ia64_pib->ib_inta);
-		ia64_set_eoi(0);
-		ia64_srlz_d();
-		vector = ia64_get_ivr();
-	}
-	ia64_srlz_d();
-
 	/* kick off the clock on this AP */
 	pcpu_initclock();
 
@@ -200,7 +256,7 @@ cpu_mp_probe(void)
 	 * case we can have multiple processors, but we simply can't wake
 	 * them up...
 	 */
-	return (mp_ncpus > 1 && ipi_vector[IPI_AP_WAKEUP] != 0);
+	return (mp_ncpus > 1 && ia64_ipi_wakeup != 0);
 }
 
 void
@@ -276,7 +332,7 @@ cpu_mp_start()
 			if (bootverbose)
 				printf("SMP: waking up cpu%d\n", pc->pc_cpuid);
 
-			ipi_send(pc, IPI_AP_WAKEUP);
+			ipi_send(pc, ia64_ipi_wakeup);
 
 			do {
 				DELAY(1000);
@@ -300,6 +356,18 @@ cpu_mp_unleash(void *dummy)
 	if (mp_ncpus <= 1)
 		return;
 
+	/* Allocate XIVs for IPIs */
+	ia64_ipi_ast = ia64_xiv_alloc(PI_DULL, IA64_XIV_IPI, ia64_ih_ast);
+	ia64_ipi_highfp = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_highfp);
+	ia64_ipi_preempt = ia64_xiv_alloc(PI_SOFT, IA64_XIV_IPI,
+	    ia64_ih_preempt);
+	ia64_ipi_rndzvs = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_rndzvs);
+	ia64_ipi_stop = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, ia64_ih_stop);
+
+	/* Reserve the NMI vector for IPI_STOP_HARD if possible */
+	ia64_ipi_nmi = (ia64_xiv_reserve(2, IA64_XIV_IPI, ia64_ih_stop) != 0)
+	    ? ia64_ipi_stop : 0x400;	/* DM=NMI, Vector=n/a */
+
 	cpus = 0;
 	smp_cpus = 0;
 	SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
@@ -361,20 +429,18 @@ ipi_all_but_self(int ipi)
  * fields are used here.
  */
 void
-ipi_send(struct pcpu *cpu, int ipi)
+ipi_send(struct pcpu *cpu, int xiv)
 {
 	u_int lid;
-	uint8_t vector;
+
+	KASSERT(xiv != 0, ("ipi_send"));
 
 	lid = LID_SAPIC(cpu->pc_md.lid);
-	vector = ipi_vector[ipi];
-	KASSERT(vector != 0, ("IPI %d is not assigned a vector", ipi));
 
 	ia64_mf();
-	ia64_st8(&(ia64_pib->ib_ipi[lid][0]), vector);
+	ia64_st8(&(ia64_pib->ib_ipi[lid][0]), xiv);
 	ia64_mf_a();
-	CTR4(KTR_SMP, "ipi_send(%p, %ld): cpuid=%d, vector=%u", cpu, ipi,
-	    PCPU_GET(cpuid), vector);
+	CTR3(KTR_SMP, "ipi_send(%p, %d): cpuid=%d", cpu, xiv, PCPU_GET(cpuid));
 }
 
 SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);

Modified: head/sys/ia64/ia64/nexus.c
==============================================================================
--- head/sys/ia64/ia64/nexus.c	Tue Mar 16 23:19:55 2010	(r205233)
+++ head/sys/ia64/ia64/nexus.c	Wed Mar 17 00:37:15 2010	(r205234)
@@ -159,41 +159,15 @@ nexus_probe(device_t dev)
 
 	device_quiet(dev);	/* suppress attach message for neatness */
 
-	/* 
-	 * XXX working notes:
-	 *
-	 * - IRQ resource creation should be moved to the PIC/APIC driver.
-	 * - DRQ resource creation should be moved to the DMAC driver.
-	 * - The above should be sorted to probe earlier than any child busses.
-	 *
-	 * - Leave I/O and memory creation here, as child probes may need them.
-	 *   (especially eg. ACPI)
-	 */
-
-	/*
-	 * IRQ's are on the mainboard on old systems, but on the ISA part
-	 * of PCI->ISA bridges.  There would be multiple sets of IRQs on
-	 * multi-ISA-bus systems.  PCI interrupts are routed to the ISA

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201003170037.o2H0bGc5043447>