162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Fast user context implementation of getcpu()
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <asm/vdso.h>
762306a36Sopenharmony_ci#include <linux/getcpu.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistatic __always_inline int read_cpu_id(void)
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	int cpu_id;
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci	__asm__ __volatile__(
1462306a36Sopenharmony_ci	"	rdtime.d $zero, %0\n"
1562306a36Sopenharmony_ci	: "=r" (cpu_id)
1662306a36Sopenharmony_ci	:
1762306a36Sopenharmony_ci	: "memory");
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	return cpu_id;
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic __always_inline const struct vdso_pcpu_data *get_pcpu_data(void)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	return (struct vdso_pcpu_data *)(get_vdso_data() + VVAR_LOONGARCH_PAGES_START * PAGE_SIZE);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciextern
2862306a36Sopenharmony_ciint __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused);
2962306a36Sopenharmony_ciint __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	int cpu_id;
3262306a36Sopenharmony_ci	const struct vdso_pcpu_data *data;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	cpu_id = read_cpu_id();
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (cpu)
3762306a36Sopenharmony_ci		*cpu = cpu_id;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (node) {
4062306a36Sopenharmony_ci		data = get_pcpu_data();
4162306a36Sopenharmony_ci		*node = data[cpu_id].node;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return 0;
4562306a36Sopenharmony_ci}
46