forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This contains the various __init C functions, the initial assembly kernel entry point, and the code to reset the system. When a file was init-related this patch contains the entire file. Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
- Loading branch information
1 parent
8caea50
commit 76d2a04
Showing
15 changed files
with
1,524 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Copyright (C) 2012 Regents of the University of California | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_BUG_H | ||
#define _ASM_RISCV_BUG_H | ||
|
||
#include <linux/compiler.h> | ||
#include <linux/const.h> | ||
#include <linux/types.h> | ||
|
||
#include <asm/asm.h> | ||
|
||
#ifdef CONFIG_GENERIC_BUG | ||
#define __BUG_INSN _AC(0x00100073, UL) /* ebreak */ | ||
|
||
#ifndef __ASSEMBLY__ | ||
typedef u32 bug_insn_t; | ||
|
||
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS | ||
#define __BUG_ENTRY_ADDR INT " 1b - 2b" | ||
#define __BUG_ENTRY_FILE INT " %0 - 2b" | ||
#else | ||
#define __BUG_ENTRY_ADDR RISCV_PTR " 1b" | ||
#define __BUG_ENTRY_FILE RISCV_PTR " %0" | ||
#endif | ||
|
||
#ifdef CONFIG_DEBUG_BUGVERBOSE | ||
#define __BUG_ENTRY \ | ||
__BUG_ENTRY_ADDR "\n\t" \ | ||
__BUG_ENTRY_FILE "\n\t" \ | ||
SHORT " %1" | ||
#else | ||
#define __BUG_ENTRY \ | ||
__BUG_ENTRY_ADDR | ||
#endif | ||
|
||
#define BUG() \ | ||
do { \ | ||
__asm__ __volatile__ ( \ | ||
"1:\n\t" \ | ||
"ebreak\n" \ | ||
".pushsection __bug_table,\"a\"\n\t" \ | ||
"2:\n\t" \ | ||
__BUG_ENTRY "\n\t" \ | ||
".org 2b + %2\n\t" \ | ||
".popsection" \ | ||
: \ | ||
: "i" (__FILE__), "i" (__LINE__), \ | ||
"i" (sizeof(struct bug_entry))); \ | ||
unreachable(); \ | ||
} while (0) | ||
#endif /* !__ASSEMBLY__ */ | ||
#else /* CONFIG_GENERIC_BUG */ | ||
#ifndef __ASSEMBLY__ | ||
#define BUG() \ | ||
do { \ | ||
__asm__ __volatile__ ("ebreak\n"); \ | ||
unreachable(); \ | ||
} while (0) | ||
#endif /* !__ASSEMBLY__ */ | ||
#endif /* CONFIG_GENERIC_BUG */ | ||
|
||
#define HAVE_ARCH_BUG | ||
|
||
#include <asm-generic/bug.h> | ||
|
||
#ifndef __ASSEMBLY__ | ||
|
||
struct pt_regs; | ||
struct task_struct; | ||
|
||
extern void die(struct pt_regs *regs, const char *str); | ||
extern void do_trap(struct pt_regs *regs, int signo, int code, | ||
unsigned long addr, struct task_struct *tsk); | ||
|
||
#endif /* !__ASSEMBLY__ */ | ||
|
||
#endif /* _ASM_RISCV_BUG_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/* | ||
* Copyright (C) 2017 Chen Liqin <liqin.chen@sunplusct.com> | ||
* Copyright (C) 2012 Regents of the University of California | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_CACHE_H | ||
#define _ASM_RISCV_CACHE_H | ||
|
||
#define L1_CACHE_SHIFT 6 | ||
|
||
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) | ||
|
||
#endif /* _ASM_RISCV_CACHE_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright (C) 2012 Regents of the University of California | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_SMP_H | ||
#define _ASM_RISCV_SMP_H | ||
|
||
/* This both needs asm-offsets.h and is used when generating it. */ | ||
#ifndef GENERATING_ASM_OFFSETS | ||
#include <asm/asm-offsets.h> | ||
#endif | ||
|
||
#include <linux/cpumask.h> | ||
#include <linux/irqreturn.h> | ||
|
||
#ifdef CONFIG_SMP | ||
|
||
/* SMP initialization hook for setup_arch */ | ||
void __init init_clockevent(void); | ||
|
||
/* SMP initialization hook for setup_arch */ | ||
void __init setup_smp(void); | ||
|
||
/* Hook for the generic smp_call_function_many() routine. */ | ||
void arch_send_call_function_ipi_mask(struct cpumask *mask); | ||
|
||
/* Hook for the generic smp_call_function_single() routine. */ | ||
void arch_send_call_function_single_ipi(int cpu); | ||
|
||
/* | ||
* This is particularly ugly: it appears we can't actually get the definition | ||
* of task_struct here, but we need access to the CPU this task is running on. | ||
* Instead of using C we're using asm-offsets.h to get the current processor | ||
* ID. | ||
*/ | ||
#define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU))) | ||
|
||
/* Interprocessor interrupt handler */ | ||
irqreturn_t handle_ipi(void); | ||
|
||
#endif /* CONFIG_SMP */ | ||
|
||
#endif /* _ASM_RISCV_SMP_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* Copyright (C) 2017 SiFive | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/cacheinfo.h> | ||
#include <linux/cpu.h> | ||
#include <linux/of.h> | ||
#include <linux/of_device.h> | ||
|
||
static void ci_leaf_init(struct cacheinfo *this_leaf, | ||
struct device_node *node, | ||
enum cache_type type, unsigned int level) | ||
{ | ||
this_leaf->of_node = node; | ||
this_leaf->level = level; | ||
this_leaf->type = type; | ||
/* not a sector cache */ | ||
this_leaf->physical_line_partition = 1; | ||
/* TODO: Add to DTS */ | ||
this_leaf->attributes = | ||
CACHE_WRITE_BACK | ||
| CACHE_READ_ALLOCATE | ||
| CACHE_WRITE_ALLOCATE; | ||
} | ||
|
||
static int __init_cache_level(unsigned int cpu) | ||
{ | ||
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); | ||
struct device_node *np = of_cpu_device_node_get(cpu); | ||
int levels = 0, leaves = 0, level; | ||
|
||
if (of_property_read_bool(np, "cache-size")) | ||
++leaves; | ||
if (of_property_read_bool(np, "i-cache-size")) | ||
++leaves; | ||
if (of_property_read_bool(np, "d-cache-size")) | ||
++leaves; | ||
if (leaves > 0) | ||
levels = 1; | ||
|
||
while ((np = of_find_next_cache_node(np))) { | ||
if (!of_device_is_compatible(np, "cache")) | ||
break; | ||
if (of_property_read_u32(np, "cache-level", &level)) | ||
break; | ||
if (level <= levels) | ||
break; | ||
if (of_property_read_bool(np, "cache-size")) | ||
++leaves; | ||
if (of_property_read_bool(np, "i-cache-size")) | ||
++leaves; | ||
if (of_property_read_bool(np, "d-cache-size")) | ||
++leaves; | ||
levels = level; | ||
} | ||
|
||
this_cpu_ci->num_levels = levels; | ||
this_cpu_ci->num_leaves = leaves; | ||
return 0; | ||
} | ||
|
||
static int __populate_cache_leaves(unsigned int cpu) | ||
{ | ||
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); | ||
struct cacheinfo *this_leaf = this_cpu_ci->info_list; | ||
struct device_node *np = of_cpu_device_node_get(cpu); | ||
int levels = 1, level = 1; | ||
|
||
if (of_property_read_bool(np, "cache-size")) | ||
ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level); | ||
if (of_property_read_bool(np, "i-cache-size")) | ||
ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level); | ||
if (of_property_read_bool(np, "d-cache-size")) | ||
ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level); | ||
|
||
while ((np = of_find_next_cache_node(np))) { | ||
if (!of_device_is_compatible(np, "cache")) | ||
break; | ||
if (of_property_read_u32(np, "cache-level", &level)) | ||
break; | ||
if (level <= levels) | ||
break; | ||
if (of_property_read_bool(np, "cache-size")) | ||
ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level); | ||
if (of_property_read_bool(np, "i-cache-size")) | ||
ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level); | ||
if (of_property_read_bool(np, "d-cache-size")) | ||
ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level); | ||
levels = level; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level) | ||
DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
* Copyright (C) 2012 Regents of the University of California | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, version 2. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/init.h> | ||
#include <linux/seq_file.h> | ||
#include <linux/of.h> | ||
|
||
/* Return -1 if not a valid hart */ | ||
int riscv_of_processor_hart(struct device_node *node) | ||
{ | ||
const char *isa, *status; | ||
u32 hart; | ||
|
||
if (!of_device_is_compatible(node, "riscv")) { | ||
pr_warn("Found incompatible CPU\n"); | ||
return -(ENODEV); | ||
} | ||
|
||
if (of_property_read_u32(node, "reg", &hart)) { | ||
pr_warn("Found CPU without hart ID\n"); | ||
return -(ENODEV); | ||
} | ||
if (hart >= NR_CPUS) { | ||
pr_info("Found hart ID %d, which is above NR_CPUs. Disabling this hart\n", hart); | ||
return -(ENODEV); | ||
} | ||
|
||
if (of_property_read_string(node, "status", &status)) { | ||
pr_warn("CPU with hartid=%d has no \"status\" property\n", hart); | ||
return -(ENODEV); | ||
} | ||
if (strcmp(status, "okay")) { | ||
pr_info("CPU with hartid=%d has a non-okay status of \"%s\"\n", hart, status); | ||
return -(ENODEV); | ||
} | ||
|
||
if (of_property_read_string(node, "riscv,isa", &isa)) { | ||
pr_warn("CPU with hartid=%d has no \"riscv,isa\" property\n", hart); | ||
return -(ENODEV); | ||
} | ||
if (isa[0] != 'r' || isa[1] != 'v') { | ||
pr_warn("CPU with hartid=%d has an invalid ISA of \"%s\"\n", hart, isa); | ||
return -(ENODEV); | ||
} | ||
|
||
return hart; | ||
} | ||
|
||
#ifdef CONFIG_PROC_FS | ||
|
||
static void *c_start(struct seq_file *m, loff_t *pos) | ||
{ | ||
*pos = cpumask_next(*pos - 1, cpu_online_mask); | ||
if ((*pos) < nr_cpu_ids) | ||
return (void *)(uintptr_t)(1 + *pos); | ||
return NULL; | ||
} | ||
|
||
static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
{ | ||
(*pos)++; | ||
return c_start(m, pos); | ||
} | ||
|
||
static void c_stop(struct seq_file *m, void *v) | ||
{ | ||
} | ||
|
||
static int c_show(struct seq_file *m, void *v) | ||
{ | ||
unsigned long hart_id = (unsigned long)v - 1; | ||
struct device_node *node = of_get_cpu_node(hart_id, NULL); | ||
const char *compat, *isa, *mmu; | ||
|
||
seq_printf(m, "hart\t: %lu\n", hart_id); | ||
if (!of_property_read_string(node, "riscv,isa", &isa) | ||
&& isa[0] == 'r' | ||
&& isa[1] == 'v') | ||
seq_printf(m, "isa\t: %s\n", isa); | ||
if (!of_property_read_string(node, "mmu-type", &mmu) | ||
&& !strncmp(mmu, "riscv,", 6)) | ||
seq_printf(m, "mmu\t: %s\n", mmu+6); | ||
if (!of_property_read_string(node, "compatible", &compat) | ||
&& strcmp(compat, "riscv")) | ||
seq_printf(m, "uarch\t: %s\n", compat); | ||
seq_puts(m, "\n"); | ||
|
||
return 0; | ||
} | ||
|
||
const struct seq_operations cpuinfo_op = { | ||
.start = c_start, | ||
.next = c_next, | ||
.stop = c_stop, | ||
.show = c_show | ||
}; | ||
|
||
#endif /* CONFIG_PROC_FS */ |
Oops, something went wrong.