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;
}