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