Contributors: 4
Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
Evan Green |
376 |
68.61% |
2 |
28.57% |
Andrew Jones |
160 |
29.20% |
3 |
42.86% |
Christophe Leroy |
10 |
1.82% |
1 |
14.29% |
Nam Cao |
2 |
0.36% |
1 |
14.29% |
Total |
548 |
|
7 |
|
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_time_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_time_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);
}