linux/arch/riscv/kernel/cpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2012 Regents of the University of California
   4 */
   5
   6#include <linux/init.h>
   7#include <linux/seq_file.h>
   8#include <linux/of.h>
   9#include <asm/smp.h>
  10
  11/*
  12 * Returns the hart ID of the given device tree node, or -ENODEV if the node
  13 * isn't an enabled and valid RISC-V hart node.
  14 */
  15int riscv_of_processor_hartid(struct device_node *node)
  16{
  17        const char *isa;
  18        u32 hart;
  19
  20        if (!of_device_is_compatible(node, "riscv")) {
  21                pr_warn("Found incompatible CPU\n");
  22                return -ENODEV;
  23        }
  24
  25        if (of_property_read_u32(node, "reg", &hart)) {
  26                pr_warn("Found CPU without hart ID\n");
  27                return -ENODEV;
  28        }
  29
  30        if (!of_device_is_available(node)) {
  31                pr_info("CPU with hartid=%d is not available\n", hart);
  32                return -ENODEV;
  33        }
  34
  35        if (of_property_read_string(node, "riscv,isa", &isa)) {
  36                pr_warn("CPU with hartid=%d has no \"riscv,isa\" property\n", hart);
  37                return -ENODEV;
  38        }
  39        if (isa[0] != 'r' || isa[1] != 'v') {
  40                pr_warn("CPU with hartid=%d has an invalid ISA of \"%s\"\n", hart, isa);
  41                return -ENODEV;
  42        }
  43
  44        return hart;
  45}
  46
  47/*
  48 * Find hart ID of the CPU DT node under which given DT node falls.
  49 *
  50 * To achieve this, we walk up the DT tree until we find an active
  51 * RISC-V core (HART) node and extract the cpuid from it.
  52 */
  53int riscv_of_parent_hartid(struct device_node *node)
  54{
  55        for (; node; node = node->parent) {
  56                if (of_device_is_compatible(node, "riscv"))
  57                        return riscv_of_processor_hartid(node);
  58        }
  59
  60        return -1;
  61}
  62
  63#ifdef CONFIG_PROC_FS
  64
  65static void print_isa(struct seq_file *f, const char *isa)
  66{
  67        /* Print the entire ISA as it is */
  68        seq_puts(f, "isa\t\t: ");
  69        seq_write(f, isa, strlen(isa));
  70        seq_puts(f, "\n");
  71}
  72
  73static void print_mmu(struct seq_file *f, const char *mmu_type)
  74{
  75#if defined(CONFIG_32BIT)
  76        if (strcmp(mmu_type, "riscv,sv32") != 0)
  77                return;
  78#elif defined(CONFIG_64BIT)
  79        if (strcmp(mmu_type, "riscv,sv39") != 0 &&
  80            strcmp(mmu_type, "riscv,sv48") != 0)
  81                return;
  82#endif
  83
  84        seq_printf(f, "mmu\t\t: %s\n", mmu_type+6);
  85}
  86
  87static void *c_start(struct seq_file *m, loff_t *pos)
  88{
  89        *pos = cpumask_next(*pos - 1, cpu_online_mask);
  90        if ((*pos) < nr_cpu_ids)
  91                return (void *)(uintptr_t)(1 + *pos);
  92        return NULL;
  93}
  94
  95static void *c_next(struct seq_file *m, void *v, loff_t *pos)
  96{
  97        (*pos)++;
  98        return c_start(m, pos);
  99}
 100
 101static void c_stop(struct seq_file *m, void *v)
 102{
 103}
 104
 105static int c_show(struct seq_file *m, void *v)
 106{
 107        unsigned long cpu_id = (unsigned long)v - 1;
 108        struct device_node *node = of_get_cpu_node(cpu_id, NULL);
 109        const char *compat, *isa, *mmu;
 110
 111        seq_printf(m, "processor\t: %lu\n", cpu_id);
 112        seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id));
 113        if (!of_property_read_string(node, "riscv,isa", &isa))
 114                print_isa(m, isa);
 115        if (!of_property_read_string(node, "mmu-type", &mmu))
 116                print_mmu(m, mmu);
 117        if (!of_property_read_string(node, "compatible", &compat)
 118            && strcmp(compat, "riscv"))
 119                seq_printf(m, "uarch\t\t: %s\n", compat);
 120        seq_puts(m, "\n");
 121        of_node_put(node);
 122
 123        return 0;
 124}
 125
 126const struct seq_operations cpuinfo_op = {
 127        .start  = c_start,
 128        .next   = c_next,
 129        .stop   = c_stop,
 130        .show   = c_show
 131};
 132
 133#endif /* CONFIG_PROC_FS */
 134