1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2023 Rivos, Inc 4 */ 5 6 #include <linux/string.h> 7 #include <linux/types.h> 8 #include <vdso/datapage.h> 9 #include <vdso/helpers.h> 10 11 extern int riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, 12 size_t cpusetsize, unsigned long *cpus, 13 unsigned int flags); 14 15 static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count, 16 size_t cpusetsize, unsigned long *cpus, 17 unsigned int flags) 18 { 19 const struct vdso_data *vd = __arch_get_vdso_data(); 20 const struct arch_vdso_time_data *avd = &vd->arch_data; 21 bool all_cpus = !cpusetsize && !cpus; 22 struct riscv_hwprobe *p = pairs; 23 struct riscv_hwprobe *end = pairs + pair_count; 24 25 /* 26 * Defer to the syscall for exotic requests. The vdso has answers 27 * stashed away only for the "all cpus" case. If all CPUs are 28 * homogeneous, then this function can handle requests for arbitrary 29 * masks. 30 */ 31 if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus)) 32 return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags); 33 34 /* This is something we can handle, fill out the pairs. */ 35 while (p < end) { 36 if (riscv_hwprobe_key_is_valid(p->key)) { 37 p->value = avd->all_cpu_hwprobe_values[p->key]; 38 39 } else { 40 p->key = -1; 41 p->value = 0; 42 } 43 44 p++; 45 } 46 47 return 0; 48 } 49 50 static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs, size_t pair_count, 51 size_t cpusetsize, unsigned long *cpus, 52 unsigned int flags) 53 { 54 const struct vdso_data *vd = __arch_get_vdso_data(); 55 const struct arch_vdso_time_data *avd = &vd->arch_data; 56 struct riscv_hwprobe *p = pairs; 57 struct riscv_hwprobe *end = pairs + pair_count; 58 unsigned char *c = (unsigned char *)cpus; 59 bool empty_cpus = true; 60 bool clear_all = false; 61 int i; 62 63 if (!cpusetsize || !cpus) 64 return -EINVAL; 65 66 for (i = 0; i < cpusetsize; i++) { 67 if (c[i]) { 68 empty_cpus = false; 69 break; 70 } 71 } 72 73 if (empty_cpus || flags != RISCV_HWPROBE_WHICH_CPUS || !avd->homogeneous_cpus) 74 return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags); 75 76 while (p < end) { 77 if (riscv_hwprobe_key_is_valid(p->key)) { 78 struct riscv_hwprobe t = { 79 .key = p->key, 80 .value = avd->all_cpu_hwprobe_values[p->key], 81 }; 82 83 if (!riscv_hwprobe_pair_cmp(&t, p)) 84 clear_all = true; 85 } else { 86 clear_all = true; 87 p->key = -1; 88 p->value = 0; 89 } 90 p++; 91 } 92 93 if (clear_all) { 94 for (i = 0; i < cpusetsize; i++) 95 c[i] = 0; 96 } 97 98 return 0; 99 } 100 101 /* Add a prototype to avoid -Wmissing-prototypes warning. */ 102 int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, 103 size_t cpusetsize, unsigned long *cpus, 104 unsigned int flags); 105 106 int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, 107 size_t cpusetsize, unsigned long *cpus, 108 unsigned int flags) 109 { 110 if (flags & RISCV_HWPROBE_WHICH_CPUS) 111 return riscv_vdso_get_cpus(pairs, pair_count, cpusetsize, 112 cpus, flags); 113 114 return riscv_vdso_get_values(pairs, pair_count, cpusetsize, 115 cpus, flags); 116 } 117