Module Name:    src
Committed By:   matt
Date:           Mon Mar  1 23:55:49 UTC 2010

Modified Files:
        src/sys/arch/sbmips/include [matt-nb5-mips64]: systemsw.h
        src/sys/arch/sbmips/sbmips [matt-nb5-mips64]: cpu.c sb1250_icu.c

Log Message:
Add MP interrupts, IPIs, and secondary CPU spinup.
(compile tested only).


To generate a diff of this commit:
cvs rdiff -u -r1.7.28.3 -r1.7.28.4 src/sys/arch/sbmips/include/systemsw.h
cvs rdiff -u -r1.18.16.4 -r1.18.16.5 src/sys/arch/sbmips/sbmips/cpu.c
cvs rdiff -u -r1.9.36.5 -r1.9.36.6 src/sys/arch/sbmips/sbmips/sb1250_icu.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/sbmips/include/systemsw.h
diff -u src/sys/arch/sbmips/include/systemsw.h:1.7.28.3 src/sys/arch/sbmips/include/systemsw.h:1.7.28.4
--- src/sys/arch/sbmips/include/systemsw.h:1.7.28.3	Tue Feb 23 20:24:37 2010
+++ src/sys/arch/sbmips/include/systemsw.h	Mon Mar  1 23:55:49 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: systemsw.h,v 1.7.28.3 2010/02/23 20:24:37 matt Exp $ */
+/* $NetBSD: systemsw.h,v 1.7.28.4 2010/03/01 23:55:49 matt Exp $ */
 
 /*
  * Copyright 2000, 2001
@@ -56,6 +56,7 @@
 bool	system_set_clockfns(void *, void (*)(void *));
 
 void	sb1250_icu_init(void);
+void	sb1250_cpu_init(struct cpu_info *);
 
 #define	cpu_intr_establish(n,s,f,a)	((*systemsw.s_intr_establish)(n,s,f,a))
 

Index: src/sys/arch/sbmips/sbmips/cpu.c
diff -u src/sys/arch/sbmips/sbmips/cpu.c:1.18.16.4 src/sys/arch/sbmips/sbmips/cpu.c:1.18.16.5
--- src/sys/arch/sbmips/sbmips/cpu.c:1.18.16.4	Sun Feb 28 23:46:18 2010
+++ src/sys/arch/sbmips/sbmips/cpu.c	Mon Mar  1 23:55:49 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.c,v 1.18.16.4 2010/02/28 23:46:18 matt Exp $ */
+/* $NetBSD: cpu.c,v 1.18.16.5 2010/03/01 23:55:49 matt Exp $ */
 
 /*
  * Copyright 2000, 2001
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.18.16.4 2010/02/28 23:46:18 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.18.16.5 2010/03/01 23:55:49 matt Exp $");
 
 #include "opt_multiprocessor.h"
 
@@ -52,6 +52,7 @@
 #include <mips/sibyte/include/sb1250_regs.h>
 #include <mips/sibyte/include/sb1250_scd.h>
 #include <mips/sibyte/dev/sbscdvar.h>
+#include <mips/cfe/cfe_api.h>
 
 #define	READ_REG(rp)		(mips3_ld((volatile uint64_t *)(rp)))
 
@@ -61,7 +62,7 @@
 CFATTACH_DECL_NEW(cpu, 0,
     cpu_match, cpu_attach, NULL, NULL);
 
-static int found = 0;
+static u_int found = 0;
 
 static int
 cpu_match(device_t parent, cfdata_t match, void *aux)
@@ -121,23 +122,44 @@
 		    (ci->ci_cpu_freq % 1000000) / 10000,
 		    ci->ci_cycles_per_hz, ci->ci_divisor_delay);
 
-		/*
-		 * If we're the primary CPU, no more work to do; we're already
-		 * running!
-		 */
-		aprint_normal("%s: ", xname);
-		cpu_identify(self);
 	} else {
 #if defined(MULTIPROCESSOR)
+		int status;
 		ci = cpu_info_alloc(NULL, found);
 		KASSERT(ci);
-		// * spinup
+
+		sb1250_cpu_init(ci);
+
+		status = cfe_cpu_start(ci->ci_cpuid, cpu_trampoline,
+		    (long) ci->ci_data.cpu_idlelwp->l_md.md_utf, 0,
+		    (long) ci);
+		if (status != 0) {
+			aprint_error(": CFE call to start failed: %d\n",
+			    status);
+		}
+		const u_long cpu_mask = 1L << cpu_index(ci);
+		for (size_t i = 0; i < 10000; i++) {
+			if (cpus_hatched & cpu_mask)
+				 break;
+			DELAY(100);
+		}
+		if ((cpus_hatched & cpu_mask) == 0) {
+			aprint_error(": failed to hatched!\n");
+			return;
+		}
 #else
-		aprint_normal("%s: processor off-line; multiprocessor support "
-		    "not present in kernel\n", xname);
+		aprint_normal_dev(self,
+		    "processor off-line; "
+		    "multiprocessor support not present in kernel\n");
 		return;
 #endif
 	}
 
+	/*
+	 * Announce ourselves.
+	 */
+	aprint_normal("%s: ", xname);
+	cpu_identify(self);
+
 	cpu_attach_common(self, ci);
 }

Index: src/sys/arch/sbmips/sbmips/sb1250_icu.c
diff -u src/sys/arch/sbmips/sbmips/sb1250_icu.c:1.9.36.5 src/sys/arch/sbmips/sbmips/sb1250_icu.c:1.9.36.6
--- src/sys/arch/sbmips/sbmips/sb1250_icu.c:1.9.36.5	Sun Feb 28 03:32:23 2010
+++ src/sys/arch/sbmips/sbmips/sb1250_icu.c	Mon Mar  1 23:55:49 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: sb1250_icu.c,v 1.9.36.5 2010/02/28 03:32:23 matt Exp $ */
+/* $NetBSD: sb1250_icu.c,v 1.9.36.6 2010/03/01 23:55:49 matt Exp $ */
 
 /*
  * Copyright 2000, 2001
@@ -33,14 +33,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sb1250_icu.c,v 1.9.36.5 2010/02/28 03:32:23 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sb1250_icu.c,v 1.9.36.6 2010/03/01 23:55:49 matt Exp $");
 
 #define	__INTR_PRIVATE
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
 
 /* XXX for uvmexp */
 #include <uvm/uvm_extern.h>
@@ -48,7 +48,9 @@
 #include <machine/systemsw.h>
 #include <mips/locore.h>
 
-/* XXX for now, this copes with one cpu only, and assumes it's CPU 0 */
+#include <mips/sibyte/include/sb1250_regs.h>
+#include <mips/sibyte/include/sb1250_int.h>
+#include <mips/sibyte/include/sb1250_scd.h>
 
 static const struct ipl_sr_map sb1250_ipl_sr_map = {
     .sr_bits = {
@@ -69,25 +71,36 @@
 };
 
 /* imr values corresponding to each pin */
-uint64_t ints_for_line[6];
-uint64_t imr_all;
+static uint64_t ints_for_ipl[_IPL_N];
+static uint64_t imr_all;
 
 struct sb1250_ihand {
-	void	(*fun)(void *, uint32_t, vaddr_t);
-	void	*arg;
-	int	level;
-	struct evcnt count;
+	void	(*ih_fun)(void *, uint32_t, vaddr_t);
+	void	*ih_arg;
+	int	ih_ipl;
 };
-static struct sb1250_ihand sb1250_ihands[64];		/* XXX */
 
-#define	SB1250_I_IMR_ADDR	(MIPS_PHYS_TO_KSEG1(0x10020000 + 0x0028))
-#define	SB1250_I_IMR_SSTATUS	(MIPS_PHYS_TO_KSEG1(0x10020000 + 0x0040))
-#define	SB1250_I_MAP(x)							\
-    (MIPS_PHYS_TO_KSEG1(0x10020000 + 0x0200 + (x) * 8))
-#define	SB1250_I_MAP_I0		0x00
-#define	SB1250_I_MAP_I1		0x01
-#define	SB1250_I_MAP_I2		0x02
-/* XXX */
+static struct sb1250_ihand sb1250_ihands[K_INT_SOURCES];
+
+#ifdef MULTIPROCESSOR
+static void sb1250_ipi_intr(void *, uint32_t, vaddr_t);
+struct evcnt *sb1250_evcnts;
+#define	INTR_EVCNTS(ci)		(&sb1250_evcnts[(ci)->ci_cpuid])
+
+#define	SB1250_I_IMR_BASE(ci)	MIPS_PHYS_TO_KSEG1(A_IMR_CPU0_BASE \
+				    + ((ci)->ci_cpuid * IMR_REGISTER_SPACING))
+#else
+struct evcnt sb1250_evcnts[K_INT_SOURCES];
+#define	INTR_EVCNTS(ci)		((void)ci, sb1250_evcnts)
+
+#define	SB1250_I_IMR_BASE(ci)	((void)ci, MIPS_PHYS_TO_KSEG1(A_IMR_CPU0_BASE))
+#endif
+#define	SB1250_I_IMR_ADDR(base)	((base) + R_IMR_INTERRUPT_MASK)
+#define	SB1250_I_IMR_SSTATUS(base) ((base) + R_IMR_INTERRUPT_SOURCE_STATUS)
+#define	SB1250_I_MAP(base, x)	((base) + R_IMR_INTERRUPT_MAP_BASE + (x) * 8)
+#define	SB1250_I_IMR_MAILBOX(base)	((base) + R_IMR_MAILBOX_CPU)
+#define	SB1250_I_IMR_MAILBOX_SET(base)	((base) + R_IMR_MAILBOX_SET_CPU)
+#define	SB1250_I_IMR_MAILBOX_CLR(base)	((base) + R_IMR_MAILBOX_CLR_CPU)
 
 #define	READ_REG(rp)		(mips3_ld((volatile uint64_t *)(rp)))
 #define	WRITE_REG(rp, val)	(mips3_sd((volatile uint64_t *)(rp), (val)))
@@ -96,42 +109,164 @@
 static void	*sb1250_intr_establish(u_int, u_int,
 		    void (*fun)(void *, uint32_t, vaddr_t), void *);
 
+static const char * const intr_names[K_INT_SOURCES] = {
+	[K_INT_WATCHDOG_TIMER_0]	= "wdog0",
+	[K_INT_WATCHDOG_TIMER_1]	= "wdog1",
+	[K_INT_TIMER_0]			= "timer0",
+	[K_INT_TIMER_1]			= "timer1",
+	[K_INT_TIMER_2]			= "timer2",
+	[K_INT_TIMER_3]			= "timer3",
+	[K_INT_SMB_0]			= "smb0",
+	[K_INT_SMB_1]			= "smb1",
+	[K_INT_UART_0]			= "uart0",
+	[K_INT_UART_1]			= "uart1",
+	[K_INT_SER_0]			= "syncser0",
+	[K_INT_SER_1]			= "syncser1",
+	[K_INT_PCMCIA]			= "pcmcia",
+	[K_INT_ADDR_TRAP]		= "addrtrap",
+	[K_INT_PERF_CNT]		= "perfcnt",
+	[K_INT_TRACE_FREEZE]		= "tracefreeze",
+	[K_INT_BAD_ECC]			= "bad ECC",
+	[K_INT_COR_ECC]			= "corrected ECC",
+	[K_INT_IO_BUS]			= "iobus",
+	[K_INT_MAC_0]			= "mac0",
+	[K_INT_MAC_1]			= "mac1",
+	[K_INT_MAC_2]			= "mac2",
+	[K_INT_DM_CH_0]			= "dmover0",
+	[K_INT_DM_CH_1]			= "dmover1",
+	[K_INT_DM_CH_2]			= "dmover2",
+	[K_INT_DM_CH_3]			= "dmover3",
+	[K_INT_MBOX_0]			= "mbox0",
+	[K_INT_MBOX_1]			= "mbox1",
+	[K_INT_MBOX_2]			= "mbox2",
+	[K_INT_MBOX_3]			= "mbox3",
+	[K_INT_CYCLE_CP0_INT]		= "zbccp0",
+	[K_INT_CYCLE_CP1_INT]		= "zbccp1",
+	[K_INT_GPIO_0]			= "gpio0",
+	[K_INT_GPIO_1]			= "gpio1",
+	[K_INT_GPIO_2]			= "gpio2",
+	[K_INT_GPIO_3]			= "gpio3",
+	[K_INT_GPIO_4]			= "gpio4",
+	[K_INT_GPIO_5]			= "gpio5",
+	[K_INT_GPIO_6]			= "gpio6",
+	[K_INT_GPIO_7]			= "gpio7",
+	[K_INT_GPIO_8]			= "gpio8",
+	[K_INT_GPIO_9]			= "gpio9",
+	[K_INT_GPIO_10]			= "gpio10",
+	[K_INT_GPIO_11]			= "gpio11",
+	[K_INT_GPIO_12]			= "gpio12",
+	[K_INT_GPIO_13]			= "gpio13",
+	[K_INT_GPIO_14]			= "gpio14",
+	[K_INT_GPIO_15]			= "gpio15",
+	[K_INT_LDT_FATAL]		= "ldt fatal",
+	[K_INT_LDT_NONFATAL]		= "ldt nonfatal",
+	[K_INT_LDT_SMI]			= "ldt smi",
+	[K_INT_LDT_NMI]			= "ldt nmi",
+	[K_INT_LDT_INIT]		= "ldt init",
+	[K_INT_LDT_STARTUP]		= "ldt startup",
+	[K_INT_LDT_EXT]			= "ldt ext",
+	[K_INT_PCI_ERROR]		= "pci error",
+	[K_INT_PCI_INTA]		= "pci inta",
+	[K_INT_PCI_INTB]		= "pci intb",
+	[K_INT_PCI_INTC]		= "pci intc",
+	[K_INT_PCI_INTD]		= "pci intd",
+	[K_INT_SPARE_2]			= "spare2",
+	[K_INT_MAC_0_CH1]		= "mac0 ch1",
+	[K_INT_MAC_1_CH1]		= "mac1 ch1",
+	[K_INT_MAC_2_CH1]		= "mac2 ch1",
+};
+
+#ifdef MULTIPROCESSOR
+static int
+sb1250_send_ipi(struct cpu_info *ci, int tag)
+{
+	const vaddr_t imr_base = SB1250_I_IMR_BASE(ci);
+	const uint64_t mbox_mask = 1LLU << tag;
+
+	WRITE_REG(SB1250_I_IMR_MAILBOX_SET(imr_base), mbox_mask);
+
+	return 0;
+}
+
+static void
+sb1250_ipi_intr(void *arg, uint32_t status, vaddr_t pc)
+{
+	struct cpu_info * const ci = curcpu();
+	const vaddr_t imr_base = SB1250_I_IMR_BASE(ci);
+	uint64_t mbox_mask;
+
+	mbox_mask = READ_REG(SB1250_I_IMR_MAILBOX(imr_base));
+	WRITE_REG(SB1250_I_IMR_MAILBOX_CLR(imr_base), mbox_mask);
+
+	ipi_process(ci, mbox_mask);
+}
+#endif
+
 void
-sb1250_icu_init(void)
+sb1250_cpu_init(struct cpu_info *ci)
 {
-	int i;
-	char *name;
+	const vaddr_t imr_base = SB1250_I_IMR_BASE(ci);
+	const char * const xname = ci->ci_dev ? device_xname(ci->ci_dev) : "cpu0";
+	struct evcnt * evcnts = INTR_EVCNTS(ci);
+	const char * const * names = intr_names;
+
+	WRITE_REG(SB1250_I_IMR_ADDR(imr_base), imr_all);
+
+	for (u_int i = 0; i < K_INT_SOURCES; i++, evcnts++, names++) {
+		WRITE_REG(SB1250_I_MAP(imr_base, i), K_INT_MAP_I0);
+		evcnt_attach_dynamic(evcnts, EVCNT_TYPE_INTR, NULL,
+		    xname, names[i]);
+	}
+}
 
+void
+sb1250_icu_init(void)
+{
 	ipl_sr_map = sb1250_ipl_sr_map;
 
 	/* zero out the list of used interrupts/lines */
-	memset(ints_for_line, 0, sizeof ints_for_line);
+	memset(ints_for_ipl, 0, sizeof ints_for_ipl);
 	imr_all = 0xffffffffffffffffULL;
 	memset(sb1250_ihands, 0, sizeof sb1250_ihands);
 
 	systemsw.s_cpu_intr = sb1250_cpu_intr;
 	systemsw.s_intr_establish = sb1250_intr_establish;
 
-	WRITE_REG(SB1250_I_IMR_ADDR, imr_all);
+#ifdef MULTIPROCESSOR
+	/*
+	 * Bits 27:24 (11:8 of G_SYS_PART) encode the number of CPUs present.
+	 */
+	u_int sys_part = G_SYS_PART(READ_REG(MIPS_PHYS_TO_KSEG1(A_SCD_SYSTEM_REVISION)));
+	const u_int cpus = (sys_part >> 8) & 0xf;
+
+	/*
+	 * Allocate an evcnt structure for every possible interrupt on
+	 * every possible CPU.
+	 */
+	sb1250_evcnts = kmem_alloc(sizeof(struct evcnt [K_INT_SOURCES*cpus]),
+	    KM_SLEEP);
+#endif /* MULTIPROCESSOR */
+
+	sb1250_cpu_init(curcpu());
+
+#ifdef MULTIPROCESSOR
+	sb1250_intr_establish(K_INT_MBOX_0, IPL_SCHED, sb1250_ipi_intr, NULL);
+	sb1250_intr_establish(K_INT_MBOX_1, IPL_SCHED, sb1250_ipi_intr, NULL);
+	sb1250_intr_establish(K_INT_MBOX_2, IPL_SCHED, sb1250_ipi_intr, NULL);
+	sb1250_intr_establish(K_INT_MBOX_3, IPL_SCHED, sb1250_ipi_intr, NULL);
 
-	for (i = 0; i < 64; i++) {
-		WRITE_REG(SB1250_I_MAP(i), SB1250_I_MAP_I0);
-		/* XXX add irq name arrays for various CPU models? */
-		name = malloc(8, M_DEVBUF, M_NOWAIT);
-		snprintf(name, 8, "irq %d", i);
-		evcnt_attach_dynamic(&sb1250_ihands[i].count, EVCNT_TYPE_INTR,
-		    NULL, "sb1250", name);	/* XXX "sb1250"? */
-	}
+	mips_locoresw.lsw_send_ipi = sb1250_send_ipi;
+#endif /* MULTIPROCESSOR */
 }
 
 static void
 sb1250_cpu_intr(int ppl, vaddr_t pc, uint32_t status)
 {
-	int i, j;
-	int ipl;
-	uint64_t sstatus;
-	uint32_t cycles;
+	struct cpu_info * const ci = curcpu();
+	const vaddr_t imr_base = SB1250_I_IMR_BASE(ci);
+	struct evcnt * const evcnts = INTR_EVCNTS(ci);
 	uint32_t pending;
+	int ipl;
 
 	uvmexp.intrs++;
 
@@ -140,25 +275,24 @@
 
 		/* XXX do something if 5? */
 		if (pending & MIPS_INT_MASK_5) {
-			cycles = mips3_cp0_count_read();
+			uint32_t cycles = mips3_cp0_count_read();
 			mips3_cp0_compare_write(cycles - 1);
 			/* just leave the bugger disabled */
 		}
 
-		for (i = 4; i >= 0; i--) {
-			if (pending & (MIPS_INT_MASK_0 << i)) {
-				sstatus = READ_REG(SB1250_I_IMR_SSTATUS);
-				sstatus &= ints_for_line[i];
-				for (j = 0; sstatus != 0 && j < 64; j++) {
-					if (sstatus & ((uint64_t)1 << j)) {
-						struct sb1250_ihand *ihp =
-						    &sb1250_ihands[j];
-						(*ihp->fun)(ihp->arg, status, pc);
-						sstatus &= ~((uint64_t)1 << j);
-						ihp->count.ev_count++;
-					}
-				}
-			}
+		uint64_t sstatus = ints_for_ipl[ipl];
+		if (sstatus == 0)
+			continue;
+
+		sstatus &= READ_REG(SB1250_I_IMR_SSTATUS(imr_base));
+		for (int j = 63; sstatus != 0; j--) {
+			u_int n = __builtin_clz(sstatus);
+			KASSERT((sstatus >> (63-n)) & 1);
+			sstatus <<= n + 1;
+			j -= n;
+			struct sb1250_ihand *ihp = &sb1250_ihands[j];
+			(*ihp->ih_fun)(ihp->ih_arg, status, pc);
+			evcnts[j].ev_count++;
 		}
 		(void) splhigh();
 	}
@@ -168,48 +302,30 @@
 sb1250_intr_establish(u_int num, u_int ipl,
     void (*fun)(void *, uint32_t, vaddr_t), void *arg)
 {
-	int s, line;
-
-	s = splhigh();
-
-	if (num >= 64)					/* XXX */
-	    panic("invalid interrupt number (0x%x)", num);
-	if (ipl >= _IPL_N)
-	    panic("invalid ipl (0x%x)", ipl);
-
-	if (sb1250_ihands[num].fun != NULL)
-	    panic("cannot share sb1250 interrupts");
-
-	/* XXX for now, everything on I0 */
-	switch (ipl) {
-#if 0
-	case IPL_NMI:
-		sr_mask = XXX;
-		break;
-	case IPL_STATCLOCK:
-		sr_mask = XXX;
-		break;
-	case IPL_CLOCK:
-		sr_mask = XXX;
-		break;
-#endif
-	default:
-		line = 0;
-		break;
-	}
+	const vaddr_t imr_base = SB1250_I_IMR_BASE(curcpu());
+	struct sb1250_ihand * const ih = &sb1250_ihands[num];
+	const int s = splhigh();
+
+	if (num >= K_INT_SOURCES)
+		panic("%s: invalid interrupt number (0x%x)", __func__, num);
+	if (ipl >= _IPL_N || ipl < IPL_VM)
+		panic("%s: invalid ipl %d", __func__, ipl);
+	if (ih->ih_fun != NULL)
+		panic("%s: cannot share sb1250 interrupts", __func__);
 
-	ints_for_line[line] |= (1ULL << num);
+	ints_for_ipl[ipl] |= (1ULL << num);
 	imr_all &= ~(1ULL << num);
 
-	/* XXX map ! */
+	ih->ih_fun = fun;
+	ih->ih_arg = arg;
+	ih->ih_ipl = ipl;
 
-	sb1250_ihands[num].fun = fun;
-	sb1250_ihands[num].arg = arg;
-	sb1250_ihands[num].level = ipl;
+	if (ipl > IPL_VM)
+		WRITE_REG(SB1250_I_MAP(imr_base, num), K_INT_MAP_I1);
 
-	WRITE_REG(SB1250_I_IMR_ADDR, imr_all);
+	WRITE_REG(SB1250_I_IMR_ADDR(imr_base), imr_all);
 
 	splx(s);
 
-	return (&sb1250_ihands[num]);
+	return ih;
 }

Reply via email to