| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright 2023 Rivos, Inc
- */
- #include <linux/string.h>
- #include <linux/types.h>
- #include <vdso/datapage.h>
- #include <vdso/helpers.h>
- extern int riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpusetsize, unsigned long *cpus,
- unsigned int flags);
- static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpusetsize, unsigned long *cpus,
- unsigned int flags)
- {
- const struct vdso_data *vd = __arch_get_vdso_data();
- const struct arch_vdso_data *avd = &vd->arch_data;
- bool all_cpus = !cpusetsize && !cpus;
- struct riscv_hwprobe *p = pairs;
- struct riscv_hwprobe *end = pairs + pair_count;
- /*
- * Defer to the syscall for exotic requests. The vdso has answers
- * stashed away only for the "all cpus" case. If all CPUs are
- * homogeneous, then this function can handle requests for arbitrary
- * masks.
- */
- if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus))
- return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
- /* This is something we can handle, fill out the pairs. */
- while (p < end) {
- if (riscv_hwprobe_key_is_valid(p->key)) {
- p->value = avd->all_cpu_hwprobe_values[p->key];
- } else {
- p->key = -1;
- p->value = 0;
- }
- p++;
- }
- return 0;
- }
- static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpusetsize, unsigned long *cpus,
- unsigned int flags)
- {
- const struct vdso_data *vd = __arch_get_vdso_data();
- const struct arch_vdso_data *avd = &vd->arch_data;
- struct riscv_hwprobe *p = pairs;
- struct riscv_hwprobe *end = pairs + pair_count;
- unsigned char *c = (unsigned char *)cpus;
- bool empty_cpus = true;
- bool clear_all = false;
- int i;
- if (!cpusetsize || !cpus)
- return -EINVAL;
- for (i = 0; i < cpusetsize; i++) {
- if (c[i]) {
- empty_cpus = false;
- break;
- }
- }
- if (empty_cpus || flags != RISCV_HWPROBE_WHICH_CPUS || !avd->homogeneous_cpus)
- return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
- while (p < end) {
- if (riscv_hwprobe_key_is_valid(p->key)) {
- struct riscv_hwprobe t = {
- .key = p->key,
- .value = avd->all_cpu_hwprobe_values[p->key],
- };
- if (!riscv_hwprobe_pair_cmp(&t, p))
- clear_all = true;
- } else {
- clear_all = true;
- p->key = -1;
- p->value = 0;
- }
- p++;
- }
- if (clear_all) {
- for (i = 0; i < cpusetsize; i++)
- c[i] = 0;
- }
- return 0;
- }
- /* Add a prototype to avoid -Wmissing-prototypes warning. */
- int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpusetsize, unsigned long *cpus,
- unsigned int flags);
- int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpusetsize, unsigned long *cpus,
- unsigned int flags)
- {
- if (flags & RISCV_HWPROBE_WHICH_CPUS)
- return riscv_vdso_get_cpus(pairs, pair_count, cpusetsize,
- cpus, flags);
- return riscv_vdso_get_values(pairs, pair_count, cpusetsize,
- cpus, flags);
- }
|