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