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 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 #ifdef CONFIG_PROC_FS 48 49 static void print_isa(struct seq_file *f, const char *orig_isa) 50 { 51 static const char *ext = "mafdcsu"; 52 const char *isa = orig_isa; 53 const char *e; 54 55 /* 56 * Linux doesn't support rv32e or rv128i, and we only support booting 57 * kernels on harts with the same ISA that the kernel is compiled for. 58 */ 59 #if defined(CONFIG_32BIT) 60 if (strncmp(isa, "rv32i", 5) != 0) 61 return; 62 #elif defined(CONFIG_64BIT) 63 if (strncmp(isa, "rv64i", 5) != 0) 64 return; 65 #endif 66 67 /* Print the base ISA, as we already know it's legal. */ 68 seq_puts(f, "isa\t\t: "); 69 seq_write(f, isa, 5); 70 isa += 5; 71 72 /* 73 * Check the rest of the ISA string for valid extensions, printing those 74 * we find. RISC-V ISA strings define an order, so we only print the 75 * extension bits when they're in order. Hide the supervisor (S) 76 * extension from userspace as it's not accessible from there. 77 */ 78 for (e = ext; *e != '\0'; ++e) { 79 if (isa[0] == e[0]) { 80 if (isa[0] != 's') 81 seq_write(f, isa, 1); 82 83 isa++; 84 } 85 } 86 seq_puts(f, "\n"); 87 88 /* 89 * If we were given an unsupported ISA in the device tree then print 90 * a bit of info describing what went wrong. 91 */ 92 if (isa[0] != '\0') 93 pr_info("unsupported ISA \"%s\" in device tree\n", orig_isa); 94 } 95 96 static void print_mmu(struct seq_file *f, const char *mmu_type) 97 { 98 #if defined(CONFIG_32BIT) 99 if (strcmp(mmu_type, "riscv,sv32") != 0) 100 return; 101 #elif defined(CONFIG_64BIT) 102 if (strcmp(mmu_type, "riscv,sv39") != 0 && 103 strcmp(mmu_type, "riscv,sv48") != 0) 104 return; 105 #endif 106 107 seq_printf(f, "mmu\t\t: %s\n", mmu_type+6); 108 } 109 110 static void *c_start(struct seq_file *m, loff_t *pos) 111 { 112 *pos = cpumask_next(*pos - 1, cpu_online_mask); 113 if ((*pos) < nr_cpu_ids) 114 return (void *)(uintptr_t)(1 + *pos); 115 return NULL; 116 } 117 118 static void *c_next(struct seq_file *m, void *v, loff_t *pos) 119 { 120 (*pos)++; 121 return c_start(m, pos); 122 } 123 124 static void c_stop(struct seq_file *m, void *v) 125 { 126 } 127 128 static int c_show(struct seq_file *m, void *v) 129 { 130 unsigned long cpu_id = (unsigned long)v - 1; 131 struct device_node *node = of_get_cpu_node(cpu_id, NULL); 132 const char *compat, *isa, *mmu; 133 134 seq_printf(m, "processor\t: %lu\n", cpu_id); 135 seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id)); 136 if (!of_property_read_string(node, "riscv,isa", &isa)) 137 print_isa(m, isa); 138 if (!of_property_read_string(node, "mmu-type", &mmu)) 139 print_mmu(m, mmu); 140 if (!of_property_read_string(node, "compatible", &compat) 141 && strcmp(compat, "riscv")) 142 seq_printf(m, "uarch\t\t: %s\n", compat); 143 seq_puts(m, "\n"); 144 of_node_put(node); 145 146 return 0; 147 } 148 149 const struct seq_operations cpuinfo_op = { 150 .start = c_start, 151 .next = c_next, 152 .stop = c_stop, 153 .show = c_show 154 }; 155 156 #endif /* CONFIG_PROC_FS */ 157