18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#ifndef __LOONGARCH_KVM_CSR_H__
78c2ecf20Sopenharmony_ci#define __LOONGARCH_KVM_CSR_H__
88c2ecf20Sopenharmony_ci#include <asm/kvm_host.h>
98c2ecf20Sopenharmony_ci#include <asm/watch.h>
108c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
118c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
128c2ecf20Sopenharmony_ci#include "kvmcpu.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define kvm_read_hw_gcsr(id)			gcsr_read(id)
158c2ecf20Sopenharmony_ci#define kvm_write_hw_gcsr(csr, id, val)		gcsr_write(val, id)
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciint _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v, int force);
188c2ecf20Sopenharmony_ciint _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v, int force);
198c2ecf20Sopenharmony_ciunsigned long _kvm_emu_read_csr(struct kvm_vcpu *vcpu, int csrid);
208c2ecf20Sopenharmony_civoid _kvm_emu_write_csr(struct kvm_vcpu *vcpu, int csrid, unsigned long val);
218c2ecf20Sopenharmony_civoid _kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid,
228c2ecf20Sopenharmony_ci	unsigned long csr_mask, unsigned long val);
238c2ecf20Sopenharmony_ciint _kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic inline void kvm_save_hw_gcsr(struct loongarch_csrs *csr, int gid)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	csr->csrs[gid] = gcsr_read(gid);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic inline void kvm_restore_hw_gcsr(struct loongarch_csrs *csr, int gid)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	gcsr_write(csr->csrs[gid], gid);
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic inline unsigned long kvm_read_sw_gcsr(struct loongarch_csrs *csr, int gid)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	return csr->csrs[gid];
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic inline void kvm_write_sw_gcsr(struct loongarch_csrs *csr, int gid, unsigned long val)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	csr->csrs[gid] = val;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic inline void kvm_set_sw_gcsr(struct loongarch_csrs *csr, int gid, unsigned long val)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	csr->csrs[gid] |= val;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline void kvm_change_sw_gcsr(struct loongarch_csrs *csr, int gid, unsigned mask,
518c2ecf20Sopenharmony_ci	unsigned long val)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	unsigned long _mask = mask;
548c2ecf20Sopenharmony_ci	csr->csrs[gid] &= ~_mask;
558c2ecf20Sopenharmony_ci	csr->csrs[gid] |= val & _mask;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define GET_HW_GCSR(id, csrid, v)				\
608c2ecf20Sopenharmony_ci	do {							\
618c2ecf20Sopenharmony_ci		if (csrid == id) {				\
628c2ecf20Sopenharmony_ci			*v = (long)kvm_read_hw_gcsr(csrid);	\
638c2ecf20Sopenharmony_ci			return 0;				\
648c2ecf20Sopenharmony_ci		}						\
658c2ecf20Sopenharmony_ci	} while (0)
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define GET_SW_GCSR(csr, id, csrid, v)				\
688c2ecf20Sopenharmony_ci	do {							\
698c2ecf20Sopenharmony_ci		if (csrid == id) {				\
708c2ecf20Sopenharmony_ci			*v = kvm_read_sw_gcsr(csr, id);		\
718c2ecf20Sopenharmony_ci			return 0;				\
728c2ecf20Sopenharmony_ci		}						\
738c2ecf20Sopenharmony_ci	} while (0)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define SET_HW_GCSR(csr, id, csrid, v)				\
768c2ecf20Sopenharmony_ci	do {							\
778c2ecf20Sopenharmony_ci		if (csrid == id) {				\
788c2ecf20Sopenharmony_ci			kvm_write_hw_gcsr(csr, csrid, *v);	\
798c2ecf20Sopenharmony_ci			return 0;				\
808c2ecf20Sopenharmony_ci		}						\
818c2ecf20Sopenharmony_ci	} while (0)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define SET_SW_GCSR(csr, id, csrid, v)				\
848c2ecf20Sopenharmony_ci	do {							\
858c2ecf20Sopenharmony_ci		if (csrid == id) {				\
868c2ecf20Sopenharmony_ci			kvm_write_sw_gcsr(csr, csrid, *v);	\
878c2ecf20Sopenharmony_ci			return 0;				\
888c2ecf20Sopenharmony_ci		}						\
898c2ecf20Sopenharmony_ci	} while (0)
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ciint _kvm_init_iocsr(struct kvm *kvm);
928c2ecf20Sopenharmony_ciint _kvm_set_iocsr(struct kvm *kvm, struct kvm_iocsr_entry *__user argp);
938c2ecf20Sopenharmony_ciint _kvm_get_iocsr(struct kvm *kvm, struct kvm_iocsr_entry *__user argp);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#define KVM_PMU_PLV_ENABLE      (CSR_PERFCTRL_PLV0 |            \
968c2ecf20Sopenharmony_ci					CSR_PERFCTRL_PLV1 |     \
978c2ecf20Sopenharmony_ci					CSR_PERFCTRL_PLV2 |     \
988c2ecf20Sopenharmony_ci					CSR_PERFCTRL_PLV3)
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#define CASE_WRITE_HW_PMU(vcpu, csr, id, csrid, v)                                 \
1018c2ecf20Sopenharmony_ci	do {                                                                            \
1028c2ecf20Sopenharmony_ci		if (csrid == id) {                                                      \
1038c2ecf20Sopenharmony_ci			if (v & KVM_PMU_PLV_ENABLE) {                                   \
1048c2ecf20Sopenharmony_ci				write_csr_gcfg(read_csr_gcfg() | CSR_GCFG_GPERF);       \
1058c2ecf20Sopenharmony_ci				kvm_write_hw_gcsr(csr, csrid, v | CSR_PERFCTRL_GMOD);   \
1068c2ecf20Sopenharmony_ci				vcpu->arch.aux_inuse |= KVM_LARCH_PERF;                 \
1078c2ecf20Sopenharmony_ci				return ;                                                \
1088c2ecf20Sopenharmony_ci			} else {                                                        \
1098c2ecf20Sopenharmony_ci				kvm_write_sw_gcsr(csr, csrid, v);                       \
1108c2ecf20Sopenharmony_ci				return;                                                 \
1118c2ecf20Sopenharmony_ci			}                                                               \
1128c2ecf20Sopenharmony_ci		}                                                                       \
1138c2ecf20Sopenharmony_ci	} while (0)
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#endif	/* __LOONGARCH_KVM_CSR_H__ */
116