Index: head/sys/conf/options.mips
===================================================================
--- head/sys/conf/options.mips (revision 332440)
+++ head/sys/conf/options.mips (revision 332441)
@@ -1,165 +1,166 @@
# Copyright (c) 2001, 2008, Juniper Networks, Inc.
# 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.
# 3. Neither the name of the Juniper Networks, Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS 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 JUNIPER NETWORKS 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.
#
# JNPR: options.mips,v 1.2 2006/09/15 12:52:34
# $FreeBSD$
CPU_MIPS4KC opt_global.h
CPU_MIPS24K opt_global.h
CPU_MIPS34K opt_global.h
CPU_MIPS74K opt_global.h
CPU_MIPS1004K opt_global.h
CPU_MIPS1074K opt_global.h
CPU_INTERAPTIV opt_global.h
CPU_PROAPTIV opt_global.h
CPU_MIPS32 opt_global.h
CPU_MIPS64 opt_global.h
CPU_SENTRY5 opt_global.h
CPU_SB1 opt_global.h
CPU_CNMIPS opt_global.h
CPU_RMI opt_global.h
CPU_NLM opt_global.h
CPU_BERI opt_global.h
CPU_XBURST opt_global.h
CPU_MALTA opt_global.h
# which MACHINE_ARCH architecture
MIPS
MIPSHF
MIPSEL
MIPSELHF
MIPS64
MIPS64HF
MIPS64EL
MIPS64ELHF
MIPSN32
COMPAT_FREEBSD32 opt_global.h
YAMON opt_global.h
CFE opt_global.h
CFE_CONSOLE opt_global.h
CFE_ENV opt_global.h
CFE_ENV_SIZE opt_global.h
GFB_DEBUG opt_gfb.h
GFB_NO_FONT_LOADING opt_gfb.h
GFB_NO_MODE_CHANGE opt_gfb.h
NOFPU opt_global.h
TICK_USE_YAMON_FREQ opt_global.h
TICK_USE_MALTA_RTC opt_global.h
#
# The highest memory address that can be used by the kernel in units of KB.
#
MAXMEM opt_global.h
#
# Manual override of cache config
#
MIPS_DISABLE_L1_CACHE opt_global.h
#
# Options that control the Cavium Simple Executive.
#
OCTEON_MODEL opt_cvmx.h
OCTEON_VENDOR_LANNER opt_cvmx.h
OCTEON_VENDOR_UBIQUITI opt_cvmx.h
OCTEON_VENDOR_RADISYS opt_cvmx.h
OCTEON_VENDOR_GEFES opt_cvmx.h
OCTEON_BOARD_CAPK_0100ND opt_cvmx.h
#
# Options specific to the BERI platform.
#
BERI_LARGE_TLB opt_global.h
+PLATFORM_INIT_SECONDARY opt_global.h
#
# Options that control the NetFPGA-10G Embedded CPU Ethernet Core.
#
NF10BMAC_64BIT opt_netfpga.h
#
# Options that control the Atheros SoC peripherals
#
ARGE_DEBUG opt_arge.h
ARGE_MDIO opt_arge.h
#
# At least one of the AR71XX ubiquiti boards has a Redboot configuration
# that "lies" about the amount of RAM it has. Until a cleaner method is
# defined, this option will suffice in overriding what Redboot says.
#
AR71XX_REALMEM opt_ar71xx.h
AR71XX_ENV_UBOOT opt_ar71xx.h
AR71XX_ENV_REDBOOT opt_ar71xx.h
AR71XX_ENV_ROUTERBOOT opt_ar71xx.h
AR71XX_ATH_EEPROM opt_ar71xx.h
#
# Options for AR531X SOC. AR531X_1ST_GENERATION is AR5311 to AR5314.
#
AR531X_1ST_GENERATION opt_ar531x.h
AR531X_REALMEM opt_ar531x.h
AR531X_ENV_UBOOT opt_ar531x.h
AR531X_APB_DEBUG opt_ar531x.h
ARE_MDIO opt_ar531x.h
ARE_MII opt_ar531x.h
#
# Options that control the Ralink RT305xF Etherenet MAC.
#
IF_RT_DEBUG opt_if_rt.h
IF_RT_PHY_SUPPORT opt_if_rt.h
IF_RT_RING_DATA_COUNT opt_if_rt.h
#
# Options that control the Ralink/Mediatek SoC type.
#
MT7620 opt_rt305x.h
RT5350 opt_rt305x.h
RT305XF opt_rt305x.h
RT3052F opt_rt305x.h
RT3050F opt_rt305x.h
RT305X opt_rt305x.h
RT305X_UBOOT opt_rt305x.h
RT305X_USE_UART opt_rt305x.h
RT_MDIO opt_rt305x.h
#
# Options that affect the pmap.
#
PV_STATS opt_pmap.h
#
# Options to use INTRNG code
#
INTRNG opt_global.h
MIPS_NIRQ opt_global.h
Index: head/sys/mips/beri/beri_mp.c
===================================================================
--- head/sys/mips/beri/beri_mp.c (nonexistent)
+++ head/sys/mips/beri/beri_mp.c (revision 332441)
@@ -0,0 +1,309 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin
+ * Copyright (c) 2012-2015 Robert N. M. Watson
+ * Copyright (c) 2013 SRI International
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * 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.
+ */
+
+#include
+__FBSDID("$FreeBSD$");
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include
+
+struct spin_entry {
+ uint64_t entry_addr;
+ uint64_t a0;
+ uint32_t rsvd1;
+ uint32_t pir;
+ uint64_t rsvd2;
+};
+
+static phandle_t cpu_of_nodes[MAXCPU];
+static device_t picmap[MAXCPU];
+
+int
+platform_processor_id(void)
+{
+ int cpu;
+
+ cpu = beri_get_cpu();
+
+ return (cpu);
+}
+
+void
+platform_cpu_mask(cpuset_t *mask)
+{
+ int ncores, ncpus, nthreads;
+ phandle_t cpus, cpu;
+ pcell_t reg;
+ char prop[16];
+ struct spin_entry *se;
+
+ ncores = beri_get_ncores();
+ nthreads = beri_get_nthreads();
+ KASSERT(ncores <= 0x10000, ("%s: too many cores %d", __func__, ncores));
+ KASSERT(nthreads <= 0x10000, ("%s: too many threads %d", __func__,
+ nthreads));
+ KASSERT(ncores < 0xffff || nthreads < 0xffff,
+ ("%s: cores x thread (%d x %d) would overflow", __func__, ncores,
+ nthreads));
+ ncpus = ncores * nthreads;
+ if (MAXCPU > 1 && ncpus > MAXCPU)
+ printf("%s: Hardware supports more CPUs (%d) than kernel (%d)\n",
+ __func__, ncpus, MAXCPU);
+ printf("%s: hardware has %d cores with %d threads each\n", __func__,
+ ncores, nthreads);
+
+ if ((cpus = OF_finddevice("/cpus")) <= 0) {
+ printf("%s: no \"/cpus\" device found in FDT\n", __func__);
+ goto error;
+ }
+ if ((cpu = OF_child(cpus)) <= 0) {
+ printf("%s: no children of \"/cpus\" found in FDT\n", __func__);
+ goto error;
+ }
+ CPU_ZERO(mask);
+ do {
+ if (OF_getprop(cpu, "reg", ®, sizeof(reg)) <= 0) {
+ printf("%s: cpu device with no reg property\n",
+ __func__);
+ goto error;
+ }
+ if (reg > MAXCPU) {
+ printf("%s: cpu ID too large (%d > %d)\n", __func__,
+ reg, MAXCPU);
+ continue;
+ }
+ cpu_of_nodes[reg] = cpu;
+
+ if (reg != 0) {
+ if (OF_getprop(cpu, "enable-method", &prop,
+ sizeof(prop)) <= 0 && OF_getprop(OF_parent(cpu),
+ "enable-method", &prop, sizeof(prop)) <= 0) {
+ printf("%s: CPU %d has no enable-method "
+ "property\n", __func__, reg);
+ continue;
+ }
+ if (strcmp("spin-table", prop) != 0) {
+ printf("%s: CPU %d enable-method is '%s' not "
+ "'spin-table'\n", __func__, reg, prop);
+ continue;
+ }
+
+ if (OF_getprop(cpu, "cpu-release-addr", &se,
+ sizeof(se)) <= 0) {
+ printf("%s: CPU %d has missing or invalid "
+ "cpu-release-addr\n", __func__, reg);
+ continue;
+ }
+ if (se->entry_addr != 1) {
+ printf("%s: CPU %d has uninitalized spin "
+ "entry\n", __func__, reg);
+ continue;
+ }
+ }
+
+ CPU_SET(reg, mask);
+ } while ((cpu = OF_peer(cpu)) > 0);
+ return;
+
+error:
+ /*
+ * If we run into any problems determining the CPU layout,
+ * fall back to UP.
+ *
+ * XXX: panic instead?
+ */
+ CPU_ZERO(mask);
+ CPU_SET(0, mask);
+}
+
+void
+platform_init_secondary(int cpuid)
+{
+ device_t ic;
+ int ipi;
+
+ ipi = platform_ipi_hardintr_num();
+
+ ic = devclass_get_device(devclass_find("beripic"), cpuid);
+ picmap[cpuid] = ic;
+ beripic_setup_ipi(ic, cpuid, ipi);
+
+ /* Unmask the interrupt */
+ if (cpuid != 0) {
+ mips_wr_status(mips_rd_status() | (((1 << ipi) << 8) << 2));
+ }
+}
+
+
+void
+platform_ipi_send(int cpuid)
+{
+
+ mips_sync(); /* Ordering, liveness. */
+
+ beripic_send_ipi(picmap[cpuid], cpuid);
+}
+
+void
+platform_ipi_clear(void)
+{
+ int cpuid;
+
+ cpuid = platform_processor_id();
+
+ beripic_clear_ipi(picmap[cpuid], cpuid);
+}
+
+/*
+ * XXXBED: Set via FDT?
+ */
+int
+platform_ipi_hardintr_num(void)
+{
+
+ return (4);
+}
+
+int
+platform_ipi_softintr_num(void)
+{
+
+ return (-1);
+}
+
+/*
+ * XXXBED: Fine for MT, will need something better for multi-core.
+ */
+struct cpu_group *
+platform_smp_topo(void)
+{
+
+ return (smp_topo_none());
+}
+
+void
+platform_init_ap(int cpuid)
+{
+ uint32_t status;
+ u_int clock_int_mask;
+
+ KASSERT(cpuid < MAXCPU, ("%s: invalid CPU id %d", __func__, cpuid));
+
+ /* Make sure coprocessors are enabled. */
+ status = mips_rd_status();
+ status |= (MIPS_SR_COP_0_BIT | MIPS_SR_COP_1_BIT);
+#if defined(CPU_CHERI)
+ status |= MIPS_SR_COP_2_BIT;
+#endif
+ mips_wr_status(status);
+
+#if 0
+ register_t hwrena;
+ /* Enable HDWRD instruction in userspace. Also enables statcounters. */
+ hwrena = mips_rd_hwrena();
+ hwrena |= (MIPS_HWRENA_CC | MIPS_HWRENA_CCRES | MIPS_HWRENA_CPUNUM |
+ MIPS_HWRENA_BERI_STATCOUNTERS_MASK);
+ mips_wr_hwrena(hwrena);
+#endif
+
+ /*
+ * Enable per-thread timer.
+ */
+ clock_int_mask = hard_int_mask(5);
+ set_intr_mask(clock_int_mask);
+}
+
+/*
+ * BERI startup conforms to the spin-table start method defined in the
+ * ePAPR 1.0 spec. The initial spin waiting for an address is started
+ * by the CPU firmware.
+ */
+int
+platform_start_ap(int cpuid)
+{
+ phandle_t cpu;
+ char prop[16];
+ struct spin_entry *se;
+
+ KASSERT(cpuid != 0, ("%s: can't start CPU 0!\n", __func__));
+ KASSERT((cpuid > 0 && cpuid < MAXCPU),
+ ("%s: invalid CPU id %d", __func__, cpuid));
+
+ cpu = cpu_of_nodes[cpuid];
+ if (OF_getprop(cpu, "status", &prop, sizeof(prop)) <= 0) {
+ if (bootverbose)
+ printf("%s: CPU %d has no status property, "
+ "trying parent\n", __func__, cpuid);
+ if (OF_getprop(OF_parent(cpu), "status", &prop,
+ sizeof(prop)) <= 0)
+ panic("%s: CPU %d has no status property", __func__,
+ cpuid);
+ }
+ if (strcmp("disabled", prop) != 0)
+ panic("%s: CPU %d status is '%s' not 'disabled'",
+ __func__, cpuid, prop);
+
+ if (OF_getprop(cpu, "enable-method", &prop, sizeof(prop)) <= 0) {
+ if (bootverbose)
+ printf("%s: CPU %d has no enable-method, "
+ "trying parent\n", __func__, cpuid);
+ if (OF_getprop(OF_parent(cpu), "enable-method", &prop,
+ sizeof(prop)) <= 0)
+ panic("%s: CPU %d has no enable-method property",
+ __func__, cpuid);
+ }
+ if (strcmp("spin-table", prop) != 0)
+ panic("%s: CPU %d enable-method is '%s' not "
+ "'spin-table'", __func__, cpuid, prop);
+
+ if (OF_getprop(cpu, "cpu-release-addr", &se, sizeof(se)) <= 0)
+ panic("%s: CPU %d has missing or invalid cpu-release-addr",
+ __func__, cpuid);
+ se->pir = cpuid;
+ if (bootverbose)
+ printf("%s: writing %p to %p\n", __func__, mpentry,
+ &se->entry_addr);
+
+ mips_sync(); /* Ordering. */
+ se->entry_addr = (intptr_t)mpentry;
+ mips_sync(); /* Liveness. */
+
+ return (0);
+}
Property changes on: head/sys/mips/beri/beri_mp.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: head/sys/mips/beri/beri_mp.h
===================================================================
--- head/sys/mips/beri/beri_mp.h (nonexistent)
+++ head/sys/mips/beri/beri_mp.h (revision 332441)
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2014 SRI International
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249)
+ * ("MRC2"), as part of the DARPA MRC research programme.
+ *
+ * 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$
+ */
+
+static inline int
+beri_get_core(void)
+{
+ uint32_t cinfo;
+
+ cinfo = mips_rd_cinfo();
+ return (cinfo & 0xffff);
+}
+
+static inline int
+beri_get_ncores(void)
+{
+ uint32_t cinfo;
+
+ cinfo = mips_rd_cinfo();
+ return ((cinfo >> 16) + 1);
+}
+
+static inline int
+beri_get_thread(void)
+{
+ uint32_t tinfo;
+
+ tinfo = mips_rd_tinfo();
+ return (tinfo & 0xffff);
+}
+
+static inline int
+beri_get_nthreads(void)
+{
+ uint32_t tinfo;
+
+ tinfo = mips_rd_tinfo();
+ return ((tinfo >> 16) + 1);
+}
+
+static inline int
+beri_get_cpu(void)
+{
+
+ return ((beri_get_core() * beri_get_nthreads()) + beri_get_thread());
+}
+
+static inline int
+beri_get_ncpus(void)
+{
+
+ return(beri_get_ncores() * beri_get_nthreads());
+}
+
+void beripic_setup_ipi(device_t dev, u_int tid, u_int ipi_irq);
+void beripic_send_ipi(device_t dev, u_int tid);
+void beripic_clear_ipi(device_t dev, u_int tid);
Property changes on: head/sys/mips/beri/beri_mp.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: head/sys/mips/beri/files.beri
===================================================================
--- head/sys/mips/beri/files.beri (revision 332440)
+++ head/sys/mips/beri/files.beri (revision 332441)
@@ -1,25 +1,26 @@
# $FreeBSD$
dev/altera/atse/if_atse.c optional altera_atse
dev/altera/atse/if_atse_fdt.c optional altera_atse fdt
dev/altera/atse/if_atse_nexus.c optional altera_atse
dev/altera/jtag_uart/altera_jtag_uart_cons.c optional altera_jtag_uart
dev/altera/jtag_uart/altera_jtag_uart_tty.c optional altera_jtag_uart
dev/altera/jtag_uart/altera_jtag_uart_fdt.c optional altera_jtag_uart fdt
dev/altera/jtag_uart/altera_jtag_uart_nexus.c optional altera_jtag_uart
dev/beri/virtio/virtio_mmio_platform.c optional virtio_mmio
dev/netfpga10g/nf10bmac/if_nf10bmac_fdt.c optional netfpga10g_nf10bmac fdt
dev/netfpga10g/nf10bmac/if_nf10bmac.c optional netfpga10g_nf10bmac
dev/terasic/de4led/terasic_de4led.c optional terasic_de4led
dev/terasic/de4led/terasic_de4led_fdt.c optional terasic_de4led fdt
dev/terasic/de4led/terasic_de4led_nexus.c optional terasic_de4led
dev/terasic/mtl/terasic_mtl.c optional terasic_mtl
dev/terasic/mtl/terasic_mtl_fdt.c optional terasic_mtl fdt
dev/terasic/mtl/terasic_mtl_nexus.c optional terasic_mtl
dev/terasic/mtl/terasic_mtl_pixel.c optional terasic_mtl
dev/terasic/mtl/terasic_mtl_reg.c optional terasic_mtl
dev/terasic/mtl/terasic_mtl_syscons.c optional terasic_mtl sc
dev/terasic/mtl/terasic_mtl_text.c optional terasic_mtl
dev/terasic/mtl/terasic_mtl_vt.c optional terasic_mtl vt
mips/beri/beri_machdep.c standard
+mips/beri/beri_mp.c optional smp
mips/beri/beri_pic.c optional fdt
mips/mips/tick.c standard
Index: head/sys/mips/beri/std.beri
===================================================================
--- head/sys/mips/beri/std.beri (revision 332440)
+++ head/sys/mips/beri/std.beri (revision 332441)
@@ -1,6 +1,7 @@
# $FreeBSD$
files "../beri/files.beri"
cpu CPU_MIPS4KC
options BERI_LARGE_TLB
+options PLATFORM_INIT_SECONDARY
Index: head/sys/mips/include/cpufunc.h
===================================================================
--- head/sys/mips/include/cpufunc.h (revision 332440)
+++ head/sys/mips/include/cpufunc.h (revision 332441)
@@ -1,396 +1,398 @@
/* $OpenBSD: pio.h,v 1.2 1998/09/15 10:50:12 pefo Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-4-Clause
*
* Copyright (c) 2002-2004 Juli Mallett. 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.
*/
/*
* Copyright (c) 1995-1999 Per Fogelstrom. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Per Fogelstrom.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
* JNPR: cpufunc.h,v 1.5 2007/08/09 11:23:32 katta
* $FreeBSD$
*/
#ifndef _MACHINE_CPUFUNC_H_
#define _MACHINE_CPUFUNC_H_
#include
#include
/*
* These functions are required by user-land atomi ops
*/
static __inline void
mips_barrier(void)
{
#if defined(CPU_CNMIPS) || defined(CPU_RMI) || defined(CPU_NLM)
__compiler_membar();
#else
__asm __volatile (".set noreorder\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
: : : "memory");
#endif
}
static __inline void
mips_cp0_sync(void)
{
__asm __volatile (__XSTRING(COP0_SYNC));
}
static __inline void
mips_wbflush(void)
{
#if defined(CPU_CNMIPS)
__asm __volatile (".set noreorder\n\t"
"syncw\n\t"
".set reorder\n"
: : : "memory");
#else
__asm __volatile ("sync" : : : "memory");
mips_barrier();
#endif
}
#ifdef _KERNEL
/*
* XXX
* It would be nice to add variants that read/write register_t, to avoid some
* ABI checks.
*/
#if defined(__mips_n32) || defined(__mips_n64)
#define MIPS_RW64_COP0(n,r) \
static __inline uint64_t \
mips_rd_ ## n (void) \
{ \
int v0; \
__asm __volatile ("dmfc0 %[v0], $"__XSTRING(r)";" \
: [v0] "=&r"(v0)); \
mips_barrier(); \
return (v0); \
} \
static __inline void \
mips_wr_ ## n (uint64_t a0) \
{ \
__asm __volatile ("dmtc0 %[a0], $"__XSTRING(r)";" \
__XSTRING(COP0_SYNC)";" \
"nop;" \
"nop;" \
: \
: [a0] "r"(a0)); \
mips_barrier(); \
} struct __hack
#define MIPS_RW64_COP0_SEL(n,r,s) \
static __inline uint64_t \
mips_rd_ ## n(void) \
{ \
int v0; \
__asm __volatile ("dmfc0 %[v0], $"__XSTRING(r)", "__XSTRING(s)";" \
: [v0] "=&r"(v0)); \
mips_barrier(); \
return (v0); \
} \
static __inline void \
mips_wr_ ## n(uint64_t a0) \
{ \
__asm __volatile ("dmtc0 %[a0], $"__XSTRING(r)", "__XSTRING(s)";" \
__XSTRING(COP0_SYNC)";" \
: \
: [a0] "r"(a0)); \
mips_barrier(); \
} struct __hack
#if defined(__mips_n64)
MIPS_RW64_COP0(excpc, MIPS_COP_0_EXC_PC);
MIPS_RW64_COP0(entryhi, MIPS_COP_0_TLB_HI);
MIPS_RW64_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK);
MIPS_RW64_COP0_SEL(userlocal, MIPS_COP_0_USERLOCAL, 2);
#ifdef CPU_CNMIPS
MIPS_RW64_COP0_SEL(cvmcount, MIPS_COP_0_COUNT, 6);
MIPS_RW64_COP0_SEL(cvmctl, MIPS_COP_0_COUNT, 7);
MIPS_RW64_COP0_SEL(cvmmemctl, MIPS_COP_0_COMPARE, 7);
MIPS_RW64_COP0_SEL(icache_err, MIPS_COP_0_CACHE_ERR, 0);
MIPS_RW64_COP0_SEL(dcache_err, MIPS_COP_0_CACHE_ERR, 1);
#endif
#endif
#if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */
MIPS_RW64_COP0(entrylo0, MIPS_COP_0_TLB_LO0);
MIPS_RW64_COP0(entrylo1, MIPS_COP_0_TLB_LO1);
#endif
MIPS_RW64_COP0(xcontext, MIPS_COP_0_TLB_XCONTEXT);
#undef MIPS_RW64_COP0
#undef MIPS_RW64_COP0_SEL
#endif
#define MIPS_RW32_COP0(n,r) \
static __inline uint32_t \
mips_rd_ ## n (void) \
{ \
int v0; \
__asm __volatile ("mfc0 %[v0], $"__XSTRING(r)";" \
: [v0] "=&r"(v0)); \
mips_barrier(); \
return (v0); \
} \
static __inline void \
mips_wr_ ## n (uint32_t a0) \
{ \
__asm __volatile ("mtc0 %[a0], $"__XSTRING(r)";" \
__XSTRING(COP0_SYNC)";" \
"nop;" \
"nop;" \
: \
: [a0] "r"(a0)); \
mips_barrier(); \
} struct __hack
#define MIPS_RW32_COP0_SEL(n,r,s) \
static __inline uint32_t \
mips_rd_ ## n(void) \
{ \
int v0; \
__asm __volatile ("mfc0 %[v0], $"__XSTRING(r)", "__XSTRING(s)";" \
: [v0] "=&r"(v0)); \
mips_barrier(); \
return (v0); \
} \
static __inline void \
mips_wr_ ## n(uint32_t a0) \
{ \
__asm __volatile ("mtc0 %[a0], $"__XSTRING(r)", "__XSTRING(s)";" \
__XSTRING(COP0_SYNC)";" \
"nop;" \
"nop;" \
: \
: [a0] "r"(a0)); \
mips_barrier(); \
} struct __hack
#ifdef CPU_CNMIPS
static __inline void mips_sync_icache (void)
{
__asm __volatile (
".set push\n"
".set mips64\n"
".word 0x041f0000\n" /* xxx ICACHE */
"nop\n"
".set pop\n"
: : );
}
#endif
MIPS_RW32_COP0(compare, MIPS_COP_0_COMPARE);
MIPS_RW32_COP0(config, MIPS_COP_0_CONFIG);
MIPS_RW32_COP0_SEL(config1, MIPS_COP_0_CONFIG, 1);
MIPS_RW32_COP0_SEL(config2, MIPS_COP_0_CONFIG, 2);
MIPS_RW32_COP0_SEL(config3, MIPS_COP_0_CONFIG, 3);
#ifdef CPU_CNMIPS
MIPS_RW32_COP0_SEL(config4, MIPS_COP_0_CONFIG, 4);
#endif
#ifdef BERI_LARGE_TLB
MIPS_RW32_COP0_SEL(config5, MIPS_COP_0_CONFIG, 5);
#endif
#if defined(CPU_NLM) || defined(BERI_LARGE_TLB)
MIPS_RW32_COP0_SEL(config6, MIPS_COP_0_CONFIG, 6);
#endif
#if defined(CPU_NLM) || defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || \
defined(CPU_MIPS24K)
MIPS_RW32_COP0_SEL(config7, MIPS_COP_0_CONFIG, 7);
#endif
MIPS_RW32_COP0(count, MIPS_COP_0_COUNT);
MIPS_RW32_COP0(index, MIPS_COP_0_TLB_INDEX);
MIPS_RW32_COP0(wired, MIPS_COP_0_TLB_WIRED);
MIPS_RW32_COP0(cause, MIPS_COP_0_CAUSE);
#if !defined(__mips_n64)
MIPS_RW32_COP0(excpc, MIPS_COP_0_EXC_PC);
#endif
MIPS_RW32_COP0(status, MIPS_COP_0_STATUS);
MIPS_RW32_COP0_SEL(cmgcrbase, 15, 3);
/* XXX: Some of these registers are specific to MIPS32. */
#if !defined(__mips_n64)
MIPS_RW32_COP0(entryhi, MIPS_COP_0_TLB_HI);
MIPS_RW32_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK);
MIPS_RW32_COP0_SEL(userlocal, MIPS_COP_0_USERLOCAL, 2);
#endif
#ifdef CPU_NLM
MIPS_RW32_COP0_SEL(pagegrain, MIPS_COP_0_TLB_PG_MASK, 1);
#endif
#if !defined(__mips_n64) && !defined(__mips_n32) /* !PHYSADDR_64_BIT */
MIPS_RW32_COP0(entrylo0, MIPS_COP_0_TLB_LO0);
MIPS_RW32_COP0(entrylo1, MIPS_COP_0_TLB_LO1);
#endif
MIPS_RW32_COP0(prid, MIPS_COP_0_PRID);
+MIPS_RW32_COP0_SEL(cinfo, MIPS_COP_0_PRID, 6);
+MIPS_RW32_COP0_SEL(tinfo, MIPS_COP_0_PRID, 7);
/* XXX 64-bit? */
MIPS_RW32_COP0_SEL(ebase, MIPS_COP_0_PRID, 1);
#if defined(CPU_MIPS24K) || defined(CPU_MIPS34K) || \
defined(CPU_MIPS74K) || defined(CPU_MIPS1004K) || \
defined(CPU_MIPS1074K) || defined(CPU_INTERAPTIV) || \
defined(CPU_PROAPTIV)
/* MIPS32/64 r2 intctl */
MIPS_RW32_COP0_SEL(intctl, MIPS_COP_0_INTCTL, 1);
#endif
#ifdef CPU_XBURST
MIPS_RW32_COP0_SEL(xburst_mbox0, MIPS_COP_0_XBURST_MBOX, 0);
MIPS_RW32_COP0_SEL(xburst_mbox1, MIPS_COP_0_XBURST_MBOX, 1);
MIPS_RW32_COP0_SEL(xburst_core_ctl, MIPS_COP_0_XBURST_C12, 2);
MIPS_RW32_COP0_SEL(xburst_core_sts, MIPS_COP_0_XBURST_C12, 3);
MIPS_RW32_COP0_SEL(xburst_reim, MIPS_COP_0_XBURST_C12, 4);
#endif
MIPS_RW32_COP0(watchlo, MIPS_COP_0_WATCH_LO);
MIPS_RW32_COP0_SEL(watchlo1, MIPS_COP_0_WATCH_LO, 1);
MIPS_RW32_COP0_SEL(watchlo2, MIPS_COP_0_WATCH_LO, 2);
MIPS_RW32_COP0_SEL(watchlo3, MIPS_COP_0_WATCH_LO, 3);
MIPS_RW32_COP0(watchhi, MIPS_COP_0_WATCH_HI);
MIPS_RW32_COP0_SEL(watchhi1, MIPS_COP_0_WATCH_HI, 1);
MIPS_RW32_COP0_SEL(watchhi2, MIPS_COP_0_WATCH_HI, 2);
MIPS_RW32_COP0_SEL(watchhi3, MIPS_COP_0_WATCH_HI, 3);
MIPS_RW32_COP0_SEL(perfcnt0, MIPS_COP_0_PERFCNT, 0);
MIPS_RW32_COP0_SEL(perfcnt1, MIPS_COP_0_PERFCNT, 1);
MIPS_RW32_COP0_SEL(perfcnt2, MIPS_COP_0_PERFCNT, 2);
MIPS_RW32_COP0_SEL(perfcnt3, MIPS_COP_0_PERFCNT, 3);
MIPS_RW32_COP0(hwrena, MIPS_COP_0_HWRENA);
#undef MIPS_RW32_COP0
#undef MIPS_RW32_COP0_SEL
static __inline register_t
intr_disable(void)
{
register_t s;
s = mips_rd_status();
mips_wr_status(s & ~MIPS_SR_INT_IE);
return (s & MIPS_SR_INT_IE);
}
static __inline register_t
intr_enable(void)
{
register_t s;
s = mips_rd_status();
mips_wr_status(s | MIPS_SR_INT_IE);
return (s);
}
static __inline void
intr_restore(register_t ie)
{
if (ie == MIPS_SR_INT_IE) {
intr_enable();
}
}
static __inline uint32_t
set_intr_mask(uint32_t mask)
{
uint32_t ostatus;
ostatus = mips_rd_status();
mask = (ostatus & ~MIPS_SR_INT_MASK) | (mask & MIPS_SR_INT_MASK);
mips_wr_status(mask);
return (ostatus);
}
static __inline uint32_t
get_intr_mask(void)
{
return (mips_rd_status() & MIPS_SR_INT_MASK);
}
static __inline void
breakpoint(void)
{
__asm __volatile ("break");
}
#if defined(__GNUC__) && !defined(__mips_o32)
#define mips3_ld(a) (*(const volatile uint64_t *)(a))
#define mips3_sd(a, v) (*(volatile uint64_t *)(a) = (v))
#else
uint64_t mips3_ld(volatile uint64_t *va);
void mips3_sd(volatile uint64_t *, uint64_t);
#endif /* __GNUC__ */
#endif /* _KERNEL */
#define readb(va) (*(volatile uint8_t *) (va))
#define readw(va) (*(volatile uint16_t *) (va))
#define readl(va) (*(volatile uint32_t *) (va))
#if defined(__GNUC__) && !defined(__mips_o32)
#define readq(a) (*(volatile uint64_t *)(a))
#endif
#define writeb(va, d) (*(volatile uint8_t *) (va) = (d))
#define writew(va, d) (*(volatile uint16_t *) (va) = (d))
#define writel(va, d) (*(volatile uint32_t *) (va) = (d))
#if defined(__GNUC__) && !defined(__mips_o32)
#define writeq(va, d) (*(volatile uint64_t *) (va) = (d))
#endif
#endif /* !_MACHINE_CPUFUNC_H_ */
Index: head/sys/mips/include/hwfunc.h
===================================================================
--- head/sys/mips/include/hwfunc.h (revision 332440)
+++ head/sys/mips/include/hwfunc.h (revision 332441)
@@ -1,104 +1,111 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2003-2004 Juli Mallett. 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_HWFUNC_H_
#define _MACHINE_HWFUNC_H_
#include
struct timecounter;
/*
* Hooks downward into platform functionality.
*/
void platform_reset(void);
void platform_start(__register_t, __register_t, __register_t, __register_t);
/* For clocks and ticks and such */
void platform_initclocks(void);
uint64_t platform_get_frequency(void);
unsigned platform_get_timecount(struct timecounter *);
/* For hardware specific CPU initialization */
void platform_cpu_init(void);
#ifdef SMP
/*
* Spin up the AP so that it starts executing MP bootstrap entry point: mpentry
*
* Returns 0 on sucess and non-zero on failure.
*/
int platform_start_ap(int processor_id);
/*
* Platform-specific initialization that needs to be done when an AP starts
* running. This function is called from the MP bootstrap code in mpboot.S
*/
void platform_init_ap(int processor_id);
/*
* Return a plaform-specific interrrupt number that is used to deliver IPIs.
*
* This hardware interrupt is used to deliver IPIs exclusively and must
* not be used for any other interrupt source.
*/
int platform_ipi_hardintr_num(void);
int platform_ipi_softintr_num(void);
+#ifdef PLATFORM_INIT_SECONDARY
+/*
+ * Set up IPIs for this CPU.
+ */
+void platform_init_secondary(int cpuid);
+#endif
+
/*
* Trigger a IPI interrupt on 'cpuid'.
*/
void platform_ipi_send(int cpuid);
/*
* Quiesce the IPI interrupt source on the current cpu.
*/
void platform_ipi_clear(void);
/*
* Return the processor id.
*
* Note that this function is called in early boot when stack is not available.
*/
extern int platform_processor_id(void);
/*
* Return the cpumask of available processors.
*/
extern void platform_cpu_mask(cpuset_t *mask);
/*
* Return the topology of processors on this platform
*/
struct cpu_group *platform_smp_topo(void);
#endif /* SMP */
#endif /* !_MACHINE_HWFUNC_H_ */
Index: head/sys/mips/mips/mp_machdep.c
===================================================================
--- head/sys/mips/mips/mp_machdep.c (revision 332440)
+++ head/sys/mips/mips/mp_machdep.c (revision 332441)
@@ -1,366 +1,374 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2009 Neelkanth Natu
* 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.
*/
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct pcb stoppcbs[MAXCPU];
static void *dpcpu;
static struct mtx ap_boot_mtx;
static volatile int aps_ready;
static volatile int mp_naps;
static void
ipi_send(struct pcpu *pc, int ipi)
{
CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi);
atomic_set_32(&pc->pc_pending_ipis, ipi);
platform_ipi_send(pc->pc_cpuid);
CTR1(KTR_SMP, "%s: sent", __func__);
}
void
ipi_all_but_self(int ipi)
{
cpuset_t other_cpus;
other_cpus = all_cpus;
CPU_CLR(PCPU_GET(cpuid), &other_cpus);
ipi_selected(other_cpus, ipi);
}
/* Send an IPI to a set of cpus. */
void
ipi_selected(cpuset_t cpus, int ipi)
{
struct pcpu *pc;
STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
if (CPU_ISSET(pc->pc_cpuid, &cpus)) {
CTR3(KTR_SMP, "%s: pc: %p, ipi: %x\n", __func__, pc,
ipi);
ipi_send(pc, ipi);
}
}
}
/* Send an IPI to a specific CPU. */
void
ipi_cpu(int cpu, u_int ipi)
{
CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x\n", __func__, cpu, ipi);
ipi_send(cpuid_to_pcpu[cpu], ipi);
}
/*
* Handle an IPI sent to this processor.
*/
static int
mips_ipi_handler(void *arg)
{
u_int cpu, ipi, ipi_bitmap;
int bit;
cpu = PCPU_GET(cpuid);
platform_ipi_clear(); /* quiesce the pending ipi interrupt */
ipi_bitmap = atomic_readandclear_int(PCPU_PTR(pending_ipis));
if (ipi_bitmap == 0)
return (FILTER_STRAY);
CTR1(KTR_SMP, "smp_handle_ipi(), ipi_bitmap=%x", ipi_bitmap);
while ((bit = ffs(ipi_bitmap))) {
bit = bit - 1;
ipi = 1 << bit;
ipi_bitmap &= ~ipi;
switch (ipi) {
case IPI_RENDEZVOUS:
CTR0(KTR_SMP, "IPI_RENDEZVOUS");
smp_rendezvous_action();
break;
case IPI_AST:
CTR0(KTR_SMP, "IPI_AST");
break;
case IPI_STOP:
/*
* IPI_STOP_HARD is mapped to IPI_STOP so it is not
* necessary to add it in the switch.
*/
CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD");
savectx(&stoppcbs[cpu]);
tlb_save();
/* Indicate we are stopped */
CPU_SET_ATOMIC(cpu, &stopped_cpus);
/* Wait for restart */
while (!CPU_ISSET(cpu, &started_cpus))
cpu_spinwait();
CPU_CLR_ATOMIC(cpu, &started_cpus);
CPU_CLR_ATOMIC(cpu, &stopped_cpus);
CTR0(KTR_SMP, "IPI_STOP (restart)");
break;
case IPI_PREEMPT:
CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
sched_preempt(curthread);
break;
case IPI_HARDCLOCK:
CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
hardclockintr();
break;
default:
panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu);
}
}
return (FILTER_HANDLED);
}
static int
start_ap(int cpuid)
{
int cpus, ms;
cpus = mp_naps;
dpcpu = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE, M_WAITOK | M_ZERO);
mips_sync();
if (platform_start_ap(cpuid) != 0)
return (-1); /* could not start AP */
for (ms = 0; ms < 5000; ++ms) {
if (mp_naps > cpus)
return (0); /* success */
else
DELAY(1000);
}
return (-2); /* timeout initializing AP */
}
void
cpu_mp_setmaxid(void)
{
cpuset_t cpumask;
int cpu, last;
platform_cpu_mask(&cpumask);
mp_ncpus = 0;
last = 1;
while ((cpu = CPU_FFS(&cpumask)) != 0) {
last = cpu;
cpu--;
CPU_CLR(cpu, &cpumask);
mp_ncpus++;
}
if (mp_ncpus <= 0)
mp_ncpus = 1;
mp_maxid = min(last, MAXCPU) - 1;
}
void
cpu_mp_announce(void)
{
/* NOTHING */
}
struct cpu_group *
cpu_topo(void)
{
return (platform_smp_topo());
}
int
cpu_mp_probe(void)
{
return (mp_ncpus > 1);
}
void
cpu_mp_start(void)
{
int error, cpuid;
cpuset_t cpumask;
mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
CPU_ZERO(&all_cpus);
platform_cpu_mask(&cpumask);
while (!CPU_EMPTY(&cpumask)) {
cpuid = CPU_FFS(&cpumask) - 1;
CPU_CLR(cpuid, &cpumask);
if (cpuid >= MAXCPU) {
printf("cpu_mp_start: ignoring AP #%d.\n", cpuid);
continue;
}
if (cpuid != platform_processor_id()) {
if ((error = start_ap(cpuid)) != 0) {
printf("AP #%d failed to start: %d\n", cpuid, error);
continue;
}
if (bootverbose)
printf("AP #%d started!\n", cpuid);
}
CPU_SET(cpuid, &all_cpus);
}
}
void
smp_init_secondary(u_int32_t cpuid)
{
/* TLB */
mips_wr_wired(0);
tlb_invalidate_all();
mips_wr_wired(VMWIRED_ENTRIES);
/*
* We assume that the L1 cache on the APs is identical to the one
* on the BSP.
*/
mips_dcache_wbinv_all();
mips_icache_sync_all();
mips_sync();
mips_wr_entryhi(0);
pcpu_init(PCPU_ADDR(cpuid), cpuid, sizeof(struct pcpu));
dpcpu_init(dpcpu, cpuid);
/* The AP has initialized successfully - allow the BSP to proceed */
++mp_naps;
/* Spin until the BSP is ready to release the APs */
while (!aps_ready)
;
+#ifdef PLATFORM_INIT_SECONDARY
+ platform_init_secondary(cpuid);
+#endif
+
/* Initialize curthread. */
KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
PCPU_SET(curthread, PCPU_GET(idlethread));
mtx_lock_spin(&ap_boot_mtx);
smp_cpus++;
CTR1(KTR_SMP, "SMP: AP CPU #%d launched", PCPU_GET(cpuid));
if (bootverbose)
printf("SMP: AP CPU #%d launched.\n", PCPU_GET(cpuid));
if (smp_cpus == mp_ncpus) {
atomic_store_rel_int(&smp_started, 1);
}
mtx_unlock_spin(&ap_boot_mtx);
while (smp_started == 0)
; /* nothing */
/* Start per-CPU event timers. */
cpu_initclocks_ap();
/* enter the scheduler */
sched_throw(NULL);
panic("scheduler returned us to %s", __func__);
/* NOTREACHED */
}
static void
release_aps(void *dummy __unused)
{
int ipi_irq;
if (mp_ncpus == 1)
return;
+
+#ifdef PLATFORM_INIT_SECONDARY
+ platform_init_secondary(0);
+#endif
/*
* IPI handler
*/
ipi_irq = platform_ipi_hardintr_num();
if (ipi_irq != -1) {
cpu_establish_hardintr("ipi", mips_ipi_handler, NULL, NULL,
ipi_irq, INTR_TYPE_MISC | INTR_EXCL, NULL);
} else {
ipi_irq = platform_ipi_softintr_num();
cpu_establish_softintr("ipi", mips_ipi_handler, NULL, NULL,
ipi_irq, INTR_TYPE_MISC | INTR_EXCL, NULL);
}
atomic_store_rel_int(&aps_ready, 1);
while (smp_started == 0)
; /* nothing */
}
SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);