Index: sys/conf/files.riscv =================================================================== --- sys/conf/files.riscv +++ sys/conf/files.riscv @@ -5,6 +5,7 @@ crypto/blowfish/bf_enc.c optional crypto | ipsec | ipsec_support crypto/des/des_enc.c optional crypto | ipsec | ipsec_support | netsmb dev/cadence/if_cgem.c optional cgem +dev/fdt/fdt_riscv_platform.c optional platform fdt dev/ofw/ofw_cpu.c optional fdt dev/ofw/ofwpci.c optional pci fdt dev/pci/pci_host_generic.c optional pci @@ -56,6 +57,8 @@ riscv/riscv/nexus.c standard riscv/riscv/ofw_machdep.c optional fdt riscv/riscv/plic.c standard +riscv/riscv/platform.c optional platform +riscv/riscv/platform_if.m optional platform riscv/riscv/pmap.c standard riscv/riscv/riscv_console.c optional rcons riscv/riscv/sbi.c standard Index: sys/conf/options.riscv =================================================================== --- sys/conf/options.riscv +++ sys/conf/options.riscv @@ -3,3 +3,4 @@ RISCV opt_global.h FPE opt_global.h INTRNG opt_global.h +PLATFORM opt_global.h Index: sys/dev/fdt/fdt_riscv_platform.c =================================================================== --- /dev/null +++ sys/dev/fdt/fdt_riscv_platform.c @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2013 Andrew Turner + * All rights reserved. + * Copyright (c) 2020 Axiado Corporation + * + * This software was developed in part by Nick O'Brien for Axiado + * Corporation. + * + * 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 "opt_platform.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "platform_if.h" + +#define FDT_PLATFORM(plat) \ + ((fdt_platform_def_t *)(plat)->cls->baseclasses[0]) + +static int +fdt_platform_probe(platform_t plat) +{ + const char *compat; + phandle_t root; + + KASSERT(plat->cls != NULL, ("Platform class is NULL")); + KASSERT(FDT_PLATFORM(plat) != NULL, ("FDT baseclass 0 is NULL")); + + /* Is the device compatible? */ + root = OF_finddevice("/"); + compat = FDT_PLATFORM(plat)->fdt_compatible; + if (ofw_bus_node_is_compatible(root, compat) != 0) + return (0); + + /* Not compatible, return an error */ + return (1); +} + +platform_method_t fdt_platform_methods[] = { + PLATFORMMETHOD(platform_probe, fdt_platform_probe), + + PLATFORMMETHOD_END +}; + Index: sys/riscv/include/platform.h =================================================================== --- /dev/null +++ sys/riscv/include/platform.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2014 Andrew Turner + * All rights reserved. + * Copyright (c) 2020 Axiado Corporation + * + * This software was developed in part by Nick O'Brien for Axiado + * Corporation. + * + * 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_PLATFORM_H_ +#define _MACHINE_PLATFORM_H_ + +/* + * Initialization functions called by the common initriscv() function in + * riscv/machdep.c + * + * - platform_probe_and_attach() is called very early, after parsing the boot + * params and after physical memory has been located and sized. + * + * - platform_devmap_init() is called as one of the last steps of early virtual + * memory initialization, shortly before the new page tables are installed. + * + * - platform_late_init() is called just after cninit(). This is the first of + * the init routines that can use printf() and expect the output to appear on + * a standard console. + * + */ + +void platform_probe_and_attach(void); +int platform_devmap_init(void); +void platform_late_init(void); + +#endif /* _MACHINE_PLATFORM_H_ */ Index: sys/riscv/include/platformvar.h =================================================================== --- /dev/null +++ sys/riscv/include/platformvar.h @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2005 Peter Grehan + * All rights reserved. + * Copyright (c) 2020 Axiado Corporation + * + * This software was developed in part by Nick O'Brien for Axiado + * Corporation. + * + * 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_PLATFORMVAR_H_ +#define _MACHINE_PLATFORMVAR_H_ + +/* + * A RISCV platform implementation is declared with a kernel object and + * an associated method table, similar to a device driver. + * + * e.g. + * + * static platform_method_t fu540_methods[] = { + * PLATFORMMETHOD(platform_probe, fu540_probe), + * ... + * PLATFORMMETHOD_END + * }; + * + * static platform_def_t fu540_platform = { + * "fu540", + * fu540_methods, + * sizeof(fu540_platform_softc), // or 0 if no softc + * }; + * + * PLATFORM_DEF(fu540_platform); + */ + +#include +#include + +struct platform_class { + KOBJ_CLASS_FIELDS; +}; + +struct platform_kobj { + /* + * A platform instance is a kernel object + */ + KOBJ_FIELDS; + + /* Platform class, for access to class specific data */ + struct platform_class *cls; +}; + +typedef struct platform_kobj *platform_t; +typedef struct platform_class platform_def_t; +#define platform_method_t kobj_method_t + +#define PLATFORMMETHOD KOBJMETHOD +#define PLATFORMMETHOD_END KOBJMETHOD_END + +#define PLATFORM_DEF(name) DATA_SET(platform_set, name) + +#ifdef FDT +struct fdt_platform_class { + KOBJ_CLASS_FIELDS; + + const char *fdt_compatible; +}; + +typedef struct fdt_platform_class fdt_platform_def_t; + +extern platform_method_t fdt_platform_methods[]; + +#define FDT_PLATFORM_DEF2(NAME, VAR_NAME, NAME_STR, _size, _compatible) \ +static fdt_platform_def_t VAR_NAME ## _fdt_platform = { \ + .name = NAME_STR, \ + .methods = fdt_platform_methods, \ + .fdt_compatible = _compatible, \ +}; \ +static kobj_class_t VAR_NAME ## _baseclasses[] = \ + { (kobj_class_t)&VAR_NAME ## _fdt_platform, NULL }; \ +static platform_def_t VAR_NAME ## _platform = { \ + .name = NAME_STR, \ + .methods = NAME ## _methods, \ + .size = _size, \ + .baseclasses = VAR_NAME ## _baseclasses, \ +}; \ +DATA_SET(platform_set, VAR_NAME ## _platform) + +#define FDT_PLATFORM_DEF(NAME, NAME_STR, size, compatible) \ + FDT_PLATFORM_DEF2(NAME, NAME, NAME_STR, size, compatible) + +#endif + +/* + * Helper to get the platform object + */ +platform_t platform_obj(void); + +#endif /* _MACHINE_PLATFORMVAR_H_ */ Index: sys/riscv/include/smp.h =================================================================== --- sys/riscv/include/smp.h +++ sys/riscv/include/smp.h @@ -54,4 +54,14 @@ extern struct pcb stoppcbs[]; +enum { + CPUS_UNKNOWN, +#ifdef FDT + CPUS_FDT, +#endif +} cpu_enum_method; + +/* Platform interface */ +void platform_mp_setmaxid(void); + #endif /* !_MACHINE_SMP_H_ */ Index: sys/riscv/riscv/machdep.c =================================================================== --- sys/riscv/riscv/machdep.c +++ sys/riscv/riscv/machdep.c @@ -82,6 +82,7 @@ #include #include #include +#include #include #include #include @@ -837,6 +838,9 @@ vm_size_t kernlen; caddr_t kmdp; int i; +#ifdef PLATFORM + int err_devmap; +#endif TSRAW(&thread0, TS_ENTER, __func__, NULL); @@ -894,7 +898,13 @@ mem_regions[i].mr_size, physmap, &physmap_idx); } } -#endif + + /* Platform-specific initialisation */ +#ifdef PLATFORM + platform_probe_and_attach(); +#endif /* PLATFORM */ + +#endif /* FDT */ /* Do basic tuning, hz etc */ init_param1(); @@ -906,10 +916,21 @@ pmap_bootstrap(rvbp->kern_l1pt, mem_regions[0].mr_start, kernlen); /* Establish static device mappings */ +#ifdef PLATFORM + err_devmap = platform_devmap_init(); +#endif devmap_bootstrap(0, NULL); cninit(); +#ifdef PLATFORM + if (err_devmap != 0) + printf("WARNING: could not fully configure devmap, error=%d\n", + err_devmap); + + platform_late_init(); +#endif + init_proc0(rvbp->kern_stack); msgbufinit(msgbufp, msgbufsize); Index: sys/riscv/riscv/mp_machdep.c =================================================================== --- sys/riscv/riscv/mp_machdep.c +++ sys/riscv/riscv/mp_machdep.c @@ -74,13 +74,6 @@ uint32_t __riscv_boot_ap[MAXCPU]; -static enum { - CPUS_UNKNOWN, -#ifdef FDT - CPUS_FDT, -#endif -} cpu_enum_method; - static device_identify_t riscv64_cpu_identify; static device_probe_t riscv64_cpu_probe; static device_attach_t riscv64_cpu_attach; @@ -456,24 +449,18 @@ { } -static boolean_t -cpu_check_mmu(u_int id, phandle_t node, u_int addr_size, pcell_t *reg) -{ - - /* Check if this hart supports MMU. */ - if (OF_getproplen(node, "mmu-type") < 0) - return (0); - - return (1); -} - void cpu_mp_setmaxid(void) { + +#ifdef PLATFORM + platform_mp_setmaxid(); +#else /* PLATFORM */ + #ifdef FDT int cores; - cores = ofw_cpu_early_foreach(cpu_check_mmu, true); + cores = ofw_cpu_early_foreach(NULL, true); if (cores > 0) { cores = MIN(cores, MAXCPU); if (bootverbose) @@ -483,10 +470,12 @@ cpu_enum_method = CPUS_FDT; return; } -#endif +#endif /* FDT */ if (bootverbose) printf("No CPU data, limiting to 1 core\n"); mp_ncpus = 1; mp_maxid = 0; + +#endif /* !PLATFORM */ } Index: sys/riscv/riscv/platform.c =================================================================== --- /dev/null +++ sys/riscv/riscv/platform.c @@ -0,0 +1,197 @@ +/*- + * Copyright (c) 2005 Peter Grehan + * Copyright (c) 2009 Nathan Whitehorn + * All rights reserved. + * Copyright (c) 2020 Axiado Coporation + * + * This software was developed in part by Nick O'Brien for Axiado + * Corporation. + * + * 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 "opt_platform.h" + +#include +__FBSDID("$FreeBSD$"); + +/* + * Dispatch platform calls to the appropriate platform implementation + * through a previously registered kernel object. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "platform_if.h" + +static platform_def_t *plat_def_impl; +static platform_t plat_obj; +static struct kobj_ops plat_kernel_kops; +static struct platform_kobj plat_kernel_obj; + +static char plat_name[64]; +SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, plat_name, 0, + "Platform currently in use"); + +/* + * Platform install routines. Highest priority wins, using the same + * algorithm as bus attachment. + */ +SET_DECLARE(platform_set, platform_def_t); + +platform_t +platform_obj(void) +{ + + return (plat_obj); +} + +void +platform_probe_and_attach(void) +{ + platform_def_t **platpp, *platp; + int prio, best_prio; + + plat_obj = &plat_kernel_obj; + best_prio = 0; + + /* + * We are unable to use TUNABLE_STR as the read will happen + * well after this function has returned. + */ + TUNABLE_STR_FETCH("hw.platform", plat_name, sizeof(plat_name)); + + /* + * Try to locate the best platform kobj + */ + SET_FOREACH(platpp, platform_set) { + platp = *platpp; + + /* + * Take care of compiling the selected class, and + * then statically initialise the MMU object + */ + kobj_class_compile_static((kobj_class_t)platp, + &plat_kernel_kops); + kobj_init_static((kobj_t)plat_obj, (kobj_class_t)platp); + + plat_obj->cls = platp; + + prio = PLATFORM_PROBE(plat_obj); + + /* Check for errors */ + if (prio > 0) + continue; + + /* + * Check if this module was specifically requested through + * the loader tunable we provide. + */ + if (strcmp(platp->name,plat_name) == 0) { + plat_def_impl = platp; + break; + } + + /* Otherwise, see if it is better than our current best */ + if (plat_def_impl == NULL || prio > best_prio) { + best_prio = prio; + plat_def_impl = platp; + } + + /* + * We can't free the KOBJ, since it is static. Reset the ops + * member of this class so that we can come back later. + */ + platp->ops = NULL; + } + + if (plat_def_impl == NULL) + panic("No platform module found!"); + + /* + * Recompile to make sure we ended with the + * correct one, and then attach. + */ + + kobj_class_compile_static((kobj_class_t)plat_def_impl, + &plat_kernel_kops); + kobj_init_static((kobj_t)plat_obj, (kobj_class_t)plat_def_impl); + + strlcpy(plat_name, plat_def_impl->name, sizeof(plat_name)); + + PLATFORM_ATTACH(plat_obj); +} + +int +platform_devmap_init(void) +{ + + return PLATFORM_DEVMAP_INIT(plat_obj); +} + +void +platform_late_init(void) +{ + + PLATFORM_LATE_INIT(plat_obj); +} + + +#if defined(SMP) +void +platform_mp_setmaxid(void) +{ + int ncpu; + + PLATFORM_MP_SETMAXID(plat_obj); + + if (TUNABLE_INT_FETCH("hw.ncpu", &ncpu)) { + if (ncpu >= 1 && ncpu <= mp_ncpus) { + mp_ncpus = ncpu; + mp_maxid = ncpu - 1; + } + } +} +#endif /* SMP */ Index: sys/riscv/riscv/platform_if.m =================================================================== --- /dev/null +++ sys/riscv/riscv/platform_if.m @@ -0,0 +1,141 @@ +#- +# Copyright (c) 2009 Nathan Whitehorn +# All rights reserved. +# Copyright (c) 2020 Axiado Corporation +# +# This software was developed in part by Nick O'Brien for Axiado +# Coporation. +# +# 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$ +# + +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef FDT +#include +#include +#endif + +/** + * @defgroup PLATFORM platform - KObj methods for RISCV platform + * implementations + * @brief A set of methods required by all platform implementations. + * These are used to supply the physical memory map, etc. + */ + +INTERFACE platform; + +# +# Default implementations +# +CODE { + static void platform_null_attach(platform_t plat) + { + return; + } + + static void platform_default_mp_setmaxid(platform_t plat) + { +#ifdef FDT + int cores; + + cores = ofw_cpu_early_foreach(NULL, true); + if (cores > 0) { + cores = MIN(cores, MAXCPU); + if (bootverbose) + printf("Found %d CPUs in the device tree\n", cores); + mp_ncpus = cores; + mp_maxid = cores - 1; + cpu_enum_method = CPUS_FDT; + return; + } +#endif + + if (bootverbose) + printf("No CPU data, limiting to 1 core\n"); + mp_ncpus = 1; + mp_maxid = 0; + } + + static int platform_default_devmap_init(platform_t plat) + { + + return (0); + } +}; + +/** + * @brief Probe for whether we are on this platform, returning the standard + * newbus probe codes. If we have Open Firmware or a flattened device tree, + * it is guaranteed to be available at this point. + */ +METHOD int probe { + platform_t _plat; +}; + +/** + * @brief Attach this platform module. This happens before the MMU is online, + * so the platform module can install its own high-priority MMU module at + * this point. + */ +METHOD int attach { + platform_t _plat; +} DEFAULT platform_null_attach; + +/** + * @brief Called as one of the last steps of early virtual memory + * initialization, shortly before the new page tables are installed. + */ +METHOD int devmap_init { + platform_t _plat; +} DEFAULT platform_default_devmap_init; + +/** + * @brief Called just after cninit(). This is the first of the init + * routines that can use printf() and expect the output to appear on + * a standard console. + */ +METHOD void late_init { + platform_t _plat; +}; + +/** + * @brief Called by cpu_mp_setmaxid() to set mp_maxid and mp_ncpus. + */ +METHOD void mp_setmaxid { + platform_t _plat; +} DEFAULT platform_default_mp_setmaxid;