1 /* 2 * Copyright (C) 2012 Regents of the University of California 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, version 2. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <linux/init.h> 15 #include <linux/seq_file.h> 16 #include <linux/of.h> 17 18 /* Return -1 if not a valid hart */ 19 int riscv_of_processor_hart(struct device_node *node) 20 { 21 const char *isa, *status; 22 u32 hart; 23 24 if (!of_device_is_compatible(node, "riscv")) { 25 pr_warn("Found incompatible CPU\n"); 26 return -(ENODEV); 27 } 28 29 if (of_property_read_u32(node, "reg", &hart)) { 30 pr_warn("Found CPU without hart ID\n"); 31 return -(ENODEV); 32 } 33 if (hart >= NR_CPUS) { 34 pr_info("Found hart ID %d, which is above NR_CPUs. Disabling this hart\n", hart); 35 return -(ENODEV); 36 } 37 38 if (of_property_read_string(node, "status", &status)) { 39 pr_warn("CPU with hartid=%d has no \"status\" property\n", hart); 40 return -(ENODEV); 41 } 42 if (strcmp(status, "okay")) { 43 pr_info("CPU with hartid=%d has a non-okay status of \"%s\"\n", hart, status); 44 return -(ENODEV); 45 } 46 47 if (of_property_read_string(node, "riscv,isa", &isa)) { 48 pr_warn("CPU with hartid=%d has no \"riscv,isa\" property\n", hart); 49 return -(ENODEV); 50 } 51 if (isa[0] != 'r' || isa[1] != 'v') { 52 pr_warn("CPU with hartid=%d has an invalid ISA of \"%s\"\n", hart, isa); 53 return -(ENODEV); 54 } 55 56 return hart; 57 } 58 59 #ifdef CONFIG_PROC_FS 60 61 static void *c_start(struct seq_file *m, loff_t *pos) 62 { 63 *pos = cpumask_next(*pos - 1, cpu_online_mask); 64 if ((*pos) < nr_cpu_ids) 65 return (void *)(uintptr_t)(1 + *pos); 66 return NULL; 67 } 68 69 static void *c_next(struct seq_file *m, void *v, loff_t *pos) 70 { 71 (*pos)++; 72 return c_start(m, pos); 73 } 74 75 static void c_stop(struct seq_file *m, void *v) 76 { 77 } 78 79 static int c_show(struct seq_file *m, void *v) 80 { 81 unsigned long hart_id = (unsigned long)v - 1; 82 struct device_node *node = of_get_cpu_node(hart_id, NULL); 83 const char *compat, *isa, *mmu; 84 85 seq_printf(m, "hart\t: %lu\n", hart_id); 86 if (!of_property_read_string(node, "riscv,isa", &isa) 87 && isa[0] == 'r' 88 && isa[1] == 'v') 89 seq_printf(m, "isa\t: %s\n", isa); 90 if (!of_property_read_string(node, "mmu-type", &mmu) 91 && !strncmp(mmu, "riscv,", 6)) 92 seq_printf(m, "mmu\t: %s\n", mmu+6); 93 if (!of_property_read_string(node, "compatible", &compat) 94 && strcmp(compat, "riscv")) 95 seq_printf(m, "uarch\t: %s\n", compat); 96 seq_puts(m, "\n"); 97 98 return 0; 99 } 100 101 const struct seq_operations cpuinfo_op = { 102 .start = c_start, 103 .next = c_next, 104 .stop = c_stop, 105 .show = c_show 106 }; 107 108 #endif /* CONFIG_PROC_FS */ 109