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#include <linux/kvm_host.h>
78c2ecf20Sopenharmony_ci#include <asm/inst.h>
88c2ecf20Sopenharmony_ci#include <asm/numa.h>
98c2ecf20Sopenharmony_ci#include "kvmcpu.h"
108c2ecf20Sopenharmony_ci#include "intc/ls3a_ipi.h"
118c2ecf20Sopenharmony_ci#include "intc/ls3a_ext_irq.h"
128c2ecf20Sopenharmony_ci#include "ls_irq.h"
138c2ecf20Sopenharmony_ci#include "kvm_compat.h"
148c2ecf20Sopenharmony_ci#include "kvmcsr.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define CASE_READ_SW_GCSR(csr, regid, csrid) \
178c2ecf20Sopenharmony_ci	do {                                          \
188c2ecf20Sopenharmony_ci		if (regid == csrid) {                     \
198c2ecf20Sopenharmony_ci			return kvm_read_sw_gcsr(csr, csrid);  \
208c2ecf20Sopenharmony_ci		}                                         \
218c2ecf20Sopenharmony_ci	} while (0)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ciunsigned long _kvm_emu_read_csr(struct kvm_vcpu *vcpu, int csrid)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
268c2ecf20Sopenharmony_ci	unsigned long val = 0;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRCTL);
298c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO1);
308c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO2);
318c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRENTRY);
328c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRERA);
338c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_MERRSAVE);
348c2ecf20Sopenharmony_ci	/* read sw csr when not config pmu to guest */
358c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL0);
368c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL1);
378c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL2);
388c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCTRL3);
398c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR0);
408c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR1);
418c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR2);
428c2ecf20Sopenharmony_ci	CASE_READ_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR3);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	val = 0;
458c2ecf20Sopenharmony_ci	if (csrid < 4096)
468c2ecf20Sopenharmony_ci		val = kvm_read_sw_gcsr(csr, csrid);
478c2ecf20Sopenharmony_ci	else
488c2ecf20Sopenharmony_ci		pr_warn_once("Unsupport csrread 0x%x with pc %lx\n",
498c2ecf20Sopenharmony_ci			csrid, vcpu->arch.pc);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return val;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define CASE_WRITE_SW_GCSR(csr, regid, csrid, val) \
558c2ecf20Sopenharmony_ci	do {                                                \
568c2ecf20Sopenharmony_ci		if (regid == csrid) {                           \
578c2ecf20Sopenharmony_ci			kvm_write_sw_gcsr(csr, csrid, val);         \
588c2ecf20Sopenharmony_ci			return ;                                    \
598c2ecf20Sopenharmony_ci		}                                               \
608c2ecf20Sopenharmony_ci	} while (0)
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_civoid _kvm_emu_write_csr(struct kvm_vcpu *vcpu, int csrid,
638c2ecf20Sopenharmony_ci	unsigned long val)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRCTL, val);
688c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO1, val);
698c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO2, val);
708c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRENTRY, val);
718c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRERA, val);
728c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_MERRSAVE, val);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* give pmu register to guest when config perfctrl */
758c2ecf20Sopenharmony_ci	CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL0, val);
768c2ecf20Sopenharmony_ci	CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL1, val);
778c2ecf20Sopenharmony_ci	CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL2, val);
788c2ecf20Sopenharmony_ci	CASE_WRITE_HW_PMU(vcpu, csr, csrid, KVM_CSR_PERFCTRL3, val);
798c2ecf20Sopenharmony_ci	/* write sw pmu csr if not config ctrl */
808c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR0, val);
818c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR1, val);
828c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR2, val);
838c2ecf20Sopenharmony_ci	CASE_WRITE_SW_GCSR(csr, csrid, KVM_CSR_PERFCNTR3, val);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (csrid < 4096)
878c2ecf20Sopenharmony_ci		kvm_write_sw_gcsr(csr, csrid, val);
888c2ecf20Sopenharmony_ci	else
898c2ecf20Sopenharmony_ci		pr_warn_once("Unsupport csrwrite 0x%x with pc %lx\n",
908c2ecf20Sopenharmony_ci				csrid, vcpu->arch.pc);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define CASE_CHANGE_SW_GCSR(csr, regid, csrid, mask, val) \
948c2ecf20Sopenharmony_ci	do {                                                       \
958c2ecf20Sopenharmony_ci		if (regid == csrid) {                                  \
968c2ecf20Sopenharmony_ci			kvm_change_sw_gcsr(csr, csrid, mask, val);         \
978c2ecf20Sopenharmony_ci			return ;                                           \
988c2ecf20Sopenharmony_ci		}                                                      \
998c2ecf20Sopenharmony_ci	} while (0)
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_civoid _kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid,
1028c2ecf20Sopenharmony_ci	unsigned long csr_mask, unsigned long val)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_IMPCTL1, csr_mask, val);
1078c2ecf20Sopenharmony_ci	CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRCTL, csr_mask, val);
1088c2ecf20Sopenharmony_ci	CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO1, csr_mask, val);
1098c2ecf20Sopenharmony_ci	CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRINFO2, csr_mask, val);
1108c2ecf20Sopenharmony_ci	CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRENTRY, csr_mask, val);
1118c2ecf20Sopenharmony_ci	CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRERA, csr_mask, val);
1128c2ecf20Sopenharmony_ci	CASE_CHANGE_SW_GCSR(csr, csrid, KVM_CSR_MERRSAVE, csr_mask, val);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (csrid < 4096) {
1158c2ecf20Sopenharmony_ci		unsigned long orig;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		orig = kvm_read_sw_gcsr(csr, csrid);
1188c2ecf20Sopenharmony_ci		orig &= ~csr_mask;
1198c2ecf20Sopenharmony_ci		orig |= val & csr_mask;
1208c2ecf20Sopenharmony_ci		kvm_write_sw_gcsr(csr, csrid, orig);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	pr_warn_once("Unsupport csrxchg 0x%x with pc %lx\n",
1238c2ecf20Sopenharmony_ci				csrid, vcpu->arch.pc);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciint _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v, int force)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_CRMD, v);
1318c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PRMD, v);
1328c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_EUEN, v);
1338c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_MISC, v);
1348c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_ECFG, v);
1358c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_ESTAT, v);
1368c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_ERA, v);
1378c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_BADV, v);
1388c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_BADI, v);
1398c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_EENTRY, v);
1408c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBIDX, v);
1418c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBEHI, v);
1428c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBELO0, v);
1438c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBELO1, v);
1448c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_ASID, v);
1458c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PGDL, v);
1468c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PGDH, v);
1478c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PWCTL0, v);
1488c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PWCTL1, v);
1498c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_STLBPGSIZE, v);
1508c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_RVACFG, v);
1518c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_CPUID, v);
1528c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PRCFG1, v);
1538c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PRCFG2, v);
1548c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_PRCFG3, v);
1558c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS0, v);
1568c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS1, v);
1578c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS2, v);
1588c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS3, v);
1598c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS4, v);
1608c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS5, v);
1618c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS6, v);
1628c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_KS7, v);
1638c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TMID, v);
1648c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TCFG, v);
1658c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TVAL, v);
1668c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_CNTC, v);
1678c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_LLBCTL, v);
1688c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBRENTRY, v);
1698c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBRBADV, v);
1708c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBRERA, v);
1718c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBRSAVE, v);
1728c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBRELO0, v);
1738c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBRELO1, v);
1748c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBREHI, v);
1758c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_TLBRPRMD, v);
1768c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_DMWIN0, v);
1778c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_DMWIN1, v);
1788c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_DMWIN2, v);
1798c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_DMWIN3, v);
1808c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_MWPS, v);
1818c2ecf20Sopenharmony_ci	GET_HW_GCSR(id, KVM_CSR_FWPS, v);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_IMPCTL1, v);
1848c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_IMPCTL2, v);
1858c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_MERRCTL, v);
1868c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_MERRINFO1, v);
1878c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_MERRINFO2, v);
1888c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_MERRENTRY, v);
1898c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_MERRERA, v);
1908c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_MERRSAVE, v);
1918c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_CTAG, v);
1928c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_DEBUG, v);
1938c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_DERA, v);
1948c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_DESAVE, v);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	GET_SW_GCSR(csr, id, KVM_CSR_TINTCLR, v);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (force && (id < CSR_ALL_SIZE)) {
1998c2ecf20Sopenharmony_ci		*v = kvm_read_sw_gcsr(csr, id);
2008c2ecf20Sopenharmony_ci		return 0;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return -1;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ciint _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v, int force)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct loongarch_csrs *csr = vcpu->arch.csr;
2098c2ecf20Sopenharmony_ci	int ret;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_CRMD, v);
2128c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_PRMD, v);
2138c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_EUEN, v);
2148c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_MISC, v);
2158c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_ECFG, v);
2168c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_ERA, v);
2178c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_BADV, v);
2188c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_BADI, v);
2198c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_EENTRY, v);
2208c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBIDX, v);
2218c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBEHI, v);
2228c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBELO0, v);
2238c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBELO1, v);
2248c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_ASID, v);
2258c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_PGDL, v);
2268c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_PGDH, v);
2278c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_PWCTL0, v);
2288c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_PWCTL1, v);
2298c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_STLBPGSIZE, v);
2308c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_RVACFG, v);
2318c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_CPUID, v);
2328c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS0, v);
2338c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS1, v);
2348c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS2, v);
2358c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS3, v);
2368c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS4, v);
2378c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS5, v);
2388c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS6, v);
2398c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_KS7, v);
2408c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TMID, v);
2418c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TCFG, v);
2428c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TVAL, v);
2438c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_CNTC, v);
2448c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_LLBCTL, v);
2458c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBRENTRY, v);
2468c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBRBADV, v);
2478c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBRERA, v);
2488c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBRSAVE, v);
2498c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBRELO0, v);
2508c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBRELO1, v);
2518c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBREHI, v);
2528c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_TLBRPRMD, v);
2538c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_DMWIN0, v);
2548c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_DMWIN1, v);
2558c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_DMWIN2, v);
2568c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_DMWIN3, v);
2578c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_MWPS, v);
2588c2ecf20Sopenharmony_ci	SET_HW_GCSR(csr, id, KVM_CSR_FWPS, v);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_IMPCTL1, v);
2618c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_IMPCTL2, v);
2628c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_MERRCTL, v);
2638c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_MERRINFO1, v);
2648c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_MERRINFO2, v);
2658c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_MERRENTRY, v);
2668c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_MERRERA, v);
2678c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_MERRSAVE, v);
2688c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_CTAG, v);
2698c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_DEBUG, v);
2708c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_DERA, v);
2718c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_DESAVE, v);
2728c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_PRCFG1, v);
2738c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_PRCFG2, v);
2748c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_PRCFG3, v);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_PGD, v);
2778c2ecf20Sopenharmony_ci	SET_SW_GCSR(csr, id, KVM_CSR_TINTCLR, v);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	ret = -1;
2808c2ecf20Sopenharmony_ci	switch (id) {
2818c2ecf20Sopenharmony_ci	case KVM_CSR_ESTAT:
2828c2ecf20Sopenharmony_ci		kvm_write_gcsr_estat(*v);
2838c2ecf20Sopenharmony_ci		/* estat IP0~IP7 inject through guestexcept */
2848c2ecf20Sopenharmony_ci		kvm_write_csr_gintc(((*v) >> 2)  & 0xff);
2858c2ecf20Sopenharmony_ci		ret = 0;
2868c2ecf20Sopenharmony_ci		break;
2878c2ecf20Sopenharmony_ci	default:
2888c2ecf20Sopenharmony_ci		if (force && (id < CSR_ALL_SIZE)) {
2898c2ecf20Sopenharmony_ci			kvm_set_sw_gcsr(csr, id, *v);
2908c2ecf20Sopenharmony_ci			ret = 0;
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci		break;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	return ret;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistruct kvm_iocsr {
2998c2ecf20Sopenharmony_ci	u32 start, end;
3008c2ecf20Sopenharmony_ci	int (*get) (struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, u64 *res);
3018c2ecf20Sopenharmony_ci	int (*set) (struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr, u64 val);
3028c2ecf20Sopenharmony_ci};
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic struct kvm_iocsr_entry *_kvm_find_iocsr(struct kvm *kvm, u32 addr)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	int i = 0;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	for (i = 0; i < IOCSR_MAX; i++) {
3098c2ecf20Sopenharmony_ci		if (addr == kvm->arch.iocsr[i].addr)
3108c2ecf20Sopenharmony_ci			return &kvm->arch.iocsr[i];
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return NULL;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int kvm_iocsr_common_get(struct kvm_run *run, struct kvm_vcpu *vcpu,
3178c2ecf20Sopenharmony_ci		u32 addr, u64 *res)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	int r = EMULATE_FAIL;
3208c2ecf20Sopenharmony_ci	struct kvm_iocsr_entry *entry;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	spin_lock(&vcpu->kvm->arch.iocsr_lock);
3238c2ecf20Sopenharmony_ci	entry = _kvm_find_iocsr(vcpu->kvm, addr);
3248c2ecf20Sopenharmony_ci	if (entry) {
3258c2ecf20Sopenharmony_ci		r = EMULATE_DONE;
3268c2ecf20Sopenharmony_ci		*res = entry->data;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci	spin_unlock(&vcpu->kvm->arch.iocsr_lock);
3298c2ecf20Sopenharmony_ci	return r;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int kvm_iocsr_common_set(struct kvm_run *run, struct kvm_vcpu *vcpu,
3338c2ecf20Sopenharmony_ci		u32 addr, u64 val)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	int r = EMULATE_FAIL;
3368c2ecf20Sopenharmony_ci	struct kvm_iocsr_entry *entry;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	spin_lock(&vcpu->kvm->arch.iocsr_lock);
3398c2ecf20Sopenharmony_ci	entry = _kvm_find_iocsr(vcpu->kvm, addr);
3408c2ecf20Sopenharmony_ci	if (entry) {
3418c2ecf20Sopenharmony_ci		r = EMULATE_DONE;
3428c2ecf20Sopenharmony_ci		entry->data = val;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	spin_unlock(&vcpu->kvm->arch.iocsr_lock);
3458c2ecf20Sopenharmony_ci	return r;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic int kvm_misc_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr,
3498c2ecf20Sopenharmony_ci		u64 val)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	return kvm_iocsr_common_set(run, vcpu, addr, val);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int kvm_ipi_get(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr,
3558c2ecf20Sopenharmony_ci		u64 *res)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	int ret;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	++vcpu->stat.rdcsr_ipi_access_exits;
3608c2ecf20Sopenharmony_ci	run->mmio.phys_addr = KVM_IPI_REG_ADDRESS(vcpu->vcpu_id, (addr & 0xff));
3618c2ecf20Sopenharmony_ci	ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
3628c2ecf20Sopenharmony_ci			run->mmio.len, res);
3638c2ecf20Sopenharmony_ci	if (ret) {
3648c2ecf20Sopenharmony_ci		run->mmio.is_write = 0;
3658c2ecf20Sopenharmony_ci		vcpu->mmio_needed = 1;
3668c2ecf20Sopenharmony_ci		vcpu->mmio_is_write = 0;
3678c2ecf20Sopenharmony_ci		return EMULATE_DO_MMIO;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci	return EMULATE_DONE;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic int kvm_extioi_isr_get(struct kvm_run *run, struct kvm_vcpu *vcpu,
3738c2ecf20Sopenharmony_ci		u32 addr, u64 *res)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	int ret;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	run->mmio.phys_addr =  EXTIOI_PERCORE_ADDR(vcpu->vcpu_id, (addr & 0xff));
3788c2ecf20Sopenharmony_ci	ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
3798c2ecf20Sopenharmony_ci			run->mmio.len, res);
3808c2ecf20Sopenharmony_ci	if (ret) {
3818c2ecf20Sopenharmony_ci		run->mmio.is_write = 0;
3828c2ecf20Sopenharmony_ci		vcpu->mmio_needed = 1;
3838c2ecf20Sopenharmony_ci		vcpu->mmio_is_write = 0;
3848c2ecf20Sopenharmony_ci		return EMULATE_FAIL;
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	return EMULATE_DONE;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int kvm_ipi_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr,
3918c2ecf20Sopenharmony_ci		u64 val)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	int ret;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	run->mmio.phys_addr = KVM_IPI_REG_ADDRESS(vcpu->vcpu_id, (addr & 0xff));
3968c2ecf20Sopenharmony_ci	ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
3978c2ecf20Sopenharmony_ci			run->mmio.len, &val);
3988c2ecf20Sopenharmony_ci	if (ret < 0) {
3998c2ecf20Sopenharmony_ci		run->mmio.is_write = 1;
4008c2ecf20Sopenharmony_ci		vcpu->mmio_needed = 1;
4018c2ecf20Sopenharmony_ci		vcpu->mmio_is_write = 1;
4028c2ecf20Sopenharmony_ci		return EMULATE_DO_MMIO;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return EMULATE_DONE;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic int kvm_extioi_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr,
4098c2ecf20Sopenharmony_ci		u64 val)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	int ret;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if ((addr & 0x1f00) == KVM_IOCSR_EXTIOI_ISR_BASE) {
4148c2ecf20Sopenharmony_ci		run->mmio.phys_addr =  EXTIOI_PERCORE_ADDR(vcpu->vcpu_id, (addr & 0xff));
4158c2ecf20Sopenharmony_ci	} else {
4168c2ecf20Sopenharmony_ci		run->mmio.phys_addr = EXTIOI_ADDR((addr & 0x1fff));
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr,
4208c2ecf20Sopenharmony_ci			run->mmio.len, &val);
4218c2ecf20Sopenharmony_ci	if (ret < 0) {
4228c2ecf20Sopenharmony_ci		memcpy(run->mmio.data, &val, run->mmio.len);
4238c2ecf20Sopenharmony_ci		run->mmio.is_write = 1;
4248c2ecf20Sopenharmony_ci		vcpu->mmio_needed = 1;
4258c2ecf20Sopenharmony_ci		vcpu->mmio_is_write = 1;
4268c2ecf20Sopenharmony_ci		return EMULATE_DO_MMIO;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return EMULATE_DONE;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int kvm_nop_set(struct kvm_run *run, struct kvm_vcpu *vcpu, u32 addr,
4338c2ecf20Sopenharmony_ci		u64 val)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	return EMULATE_DONE;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/* we put these iocsrs with access frequency, from high to low */
4398c2ecf20Sopenharmony_cistatic struct kvm_iocsr kvm_iocsrs[] = {
4408c2ecf20Sopenharmony_ci	/* extioi iocsr */
4418c2ecf20Sopenharmony_ci	{KVM_IOCSR_EXTIOI_EN_BASE, KVM_IOCSR_EXTIOI_EN_BASE + 0x100,
4428c2ecf20Sopenharmony_ci		NULL, kvm_extioi_set},
4438c2ecf20Sopenharmony_ci	{KVM_IOCSR_EXTIOI_NODEMAP_BASE, KVM_IOCSR_EXTIOI_NODEMAP_BASE+0x28,
4448c2ecf20Sopenharmony_ci		NULL, kvm_extioi_set},
4458c2ecf20Sopenharmony_ci	{KVM_IOCSR_EXTIOI_ROUTE_BASE, KVM_IOCSR_EXTIOI_ROUTE_BASE + 0x100,
4468c2ecf20Sopenharmony_ci		NULL, kvm_extioi_set},
4478c2ecf20Sopenharmony_ci	{KVM_IOCSR_EXTIOI_ISR_BASE, KVM_IOCSR_EXTIOI_ISR_BASE + 0x1c,
4488c2ecf20Sopenharmony_ci		kvm_extioi_isr_get, kvm_extioi_set},
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	{KVM_IOCSR_IPI_STATUS, KVM_IOCSR_IPI_STATUS + 0x40,
4518c2ecf20Sopenharmony_ci		kvm_ipi_get, kvm_ipi_set},
4528c2ecf20Sopenharmony_ci	{KVM_IOCSR_IPI_SEND, KVM_IOCSR_IPI_SEND + 0x1,
4538c2ecf20Sopenharmony_ci		NULL, kvm_ipi_set},
4548c2ecf20Sopenharmony_ci	{KVM_IOCSR_MBUF_SEND, KVM_IOCSR_MBUF_SEND + 0x1,
4558c2ecf20Sopenharmony_ci		NULL, kvm_ipi_set},
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	{KVM_IOCSR_FEATURES, KVM_IOCSR_FEATURES + 0x1,
4588c2ecf20Sopenharmony_ci		kvm_iocsr_common_get, kvm_nop_set},
4598c2ecf20Sopenharmony_ci	{KVM_IOCSR_VENDOR, KVM_IOCSR_VENDOR + 0x1,
4608c2ecf20Sopenharmony_ci		kvm_iocsr_common_get, kvm_nop_set},
4618c2ecf20Sopenharmony_ci	{KVM_IOCSR_CPUNAME, KVM_IOCSR_CPUNAME + 0x1,
4628c2ecf20Sopenharmony_ci		kvm_iocsr_common_get, kvm_nop_set},
4638c2ecf20Sopenharmony_ci	{KVM_IOCSR_NODECNT, KVM_IOCSR_NODECNT + 0x1,
4648c2ecf20Sopenharmony_ci		kvm_iocsr_common_get, kvm_nop_set},
4658c2ecf20Sopenharmony_ci	{KVM_IOCSR_MISC_FUNC, KVM_IOCSR_MISC_FUNC + 0x1,
4668c2ecf20Sopenharmony_ci		kvm_iocsr_common_get, kvm_misc_set},
4678c2ecf20Sopenharmony_ci};
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int _kvm_emu_iocsr_read(struct kvm_run *run, struct kvm_vcpu *vcpu,
4708c2ecf20Sopenharmony_ci		u32 addr, u64 *res)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	enum emulation_result er = EMULATE_FAIL;
4738c2ecf20Sopenharmony_ci	int i = 0;
4748c2ecf20Sopenharmony_ci	struct kvm_iocsr *iocsr = NULL;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (!irqchip_in_kernel(vcpu->kvm)) {
4778c2ecf20Sopenharmony_ci		run->iocsr_io.len = run->mmio.len;
4788c2ecf20Sopenharmony_ci		run->iocsr_io.phys_addr = addr;
4798c2ecf20Sopenharmony_ci		run->iocsr_io.is_write = 0;
4808c2ecf20Sopenharmony_ci		return EMULATE_DO_IOCSR;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci	for (i = 0; i < sizeof(kvm_iocsrs) / sizeof(struct kvm_iocsr); i++) {
4838c2ecf20Sopenharmony_ci		iocsr = &kvm_iocsrs[i];
4848c2ecf20Sopenharmony_ci		if (addr >= iocsr->start && addr < iocsr->end) {
4858c2ecf20Sopenharmony_ci			if (iocsr->get)
4868c2ecf20Sopenharmony_ci				er = iocsr->get(run, vcpu, addr, res);
4878c2ecf20Sopenharmony_ci		}
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (er != EMULATE_DONE)
4918c2ecf20Sopenharmony_ci		kvm_debug("%s iocsr 0x%x not support in kvm\n", __func__, addr);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	return er;
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic int _kvm_emu_iocsr_write(struct kvm_run *run, struct kvm_vcpu *vcpu,
4978c2ecf20Sopenharmony_ci		u32 addr, u64 val)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	enum emulation_result er = EMULATE_FAIL;
5008c2ecf20Sopenharmony_ci	int i = 0;
5018c2ecf20Sopenharmony_ci	struct kvm_iocsr *iocsr = NULL;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (!irqchip_in_kernel(vcpu->kvm)) {
5048c2ecf20Sopenharmony_ci		run->iocsr_io.len = run->mmio.len;
5058c2ecf20Sopenharmony_ci		memcpy(run->iocsr_io.data, &val, run->iocsr_io.len);
5068c2ecf20Sopenharmony_ci		run->iocsr_io.phys_addr = addr;
5078c2ecf20Sopenharmony_ci		run->iocsr_io.is_write = 1;
5088c2ecf20Sopenharmony_ci		return EMULATE_DO_IOCSR;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci	for (i = 0; i < sizeof(kvm_iocsrs) / sizeof(struct kvm_iocsr); i++) {
5118c2ecf20Sopenharmony_ci		iocsr = &kvm_iocsrs[i];
5128c2ecf20Sopenharmony_ci		if (addr >= iocsr->start && addr < iocsr->end) {
5138c2ecf20Sopenharmony_ci			if (iocsr->set)
5148c2ecf20Sopenharmony_ci				er = iocsr->set(run, vcpu, addr, val);
5158c2ecf20Sopenharmony_ci		}
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	if (er != EMULATE_DONE)
5188c2ecf20Sopenharmony_ci		kvm_debug("%s iocsr 0x%x not support in kvm\n", __func__, addr);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return er;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci/* all iocsr operation should in kvm, no mmio */
5248c2ecf20Sopenharmony_ciint _kvm_emu_iocsr(larch_inst inst,
5258c2ecf20Sopenharmony_ci		struct kvm_run *run, struct kvm_vcpu *vcpu)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	u32 rd, rj, opcode;
5288c2ecf20Sopenharmony_ci	u32 val;
5298c2ecf20Sopenharmony_ci	u64 res = 0;
5308c2ecf20Sopenharmony_ci	int ret;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/*
5338c2ecf20Sopenharmony_ci	 * Each IOCSR with different opcode
5348c2ecf20Sopenharmony_ci	 */
5358c2ecf20Sopenharmony_ci	rd = inst.reg2_format.rd;
5368c2ecf20Sopenharmony_ci	rj = inst.reg2_format.rj;
5378c2ecf20Sopenharmony_ci	opcode = inst.reg2_format.opcode;
5388c2ecf20Sopenharmony_ci	val = vcpu->arch.gprs[rj];
5398c2ecf20Sopenharmony_ci	res = vcpu->arch.gprs[rd];
5408c2ecf20Sopenharmony_ci	/* LoongArch is Little endian */
5418c2ecf20Sopenharmony_ci	switch (opcode) {
5428c2ecf20Sopenharmony_ci	case iocsrrdb_op:
5438c2ecf20Sopenharmony_ci		run->mmio.len = 1;
5448c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_read(run, vcpu, val, &res);
5458c2ecf20Sopenharmony_ci		vcpu->arch.gprs[rd] = (u8) res;
5468c2ecf20Sopenharmony_ci		break;
5478c2ecf20Sopenharmony_ci	case iocsrrdh_op:
5488c2ecf20Sopenharmony_ci		run->mmio.len = 2;
5498c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_read(run, vcpu, val, &res);
5508c2ecf20Sopenharmony_ci		vcpu->arch.gprs[rd] = (u16) res;
5518c2ecf20Sopenharmony_ci		break;
5528c2ecf20Sopenharmony_ci	case iocsrrdw_op:
5538c2ecf20Sopenharmony_ci		run->mmio.len = 4;
5548c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_read(run, vcpu, val, &res);
5558c2ecf20Sopenharmony_ci		vcpu->arch.gprs[rd] = (u32) res;
5568c2ecf20Sopenharmony_ci		break;
5578c2ecf20Sopenharmony_ci	case iocsrrdd_op:
5588c2ecf20Sopenharmony_ci		run->mmio.len = 8;
5598c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_read(run, vcpu, val, &res);
5608c2ecf20Sopenharmony_ci		vcpu->arch.gprs[rd] = res;
5618c2ecf20Sopenharmony_ci		break;
5628c2ecf20Sopenharmony_ci	case iocsrwrb_op:
5638c2ecf20Sopenharmony_ci		run->mmio.len = 1;
5648c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_write(run, vcpu, val, (u8)res);
5658c2ecf20Sopenharmony_ci		break;
5668c2ecf20Sopenharmony_ci	case iocsrwrh_op:
5678c2ecf20Sopenharmony_ci		run->mmio.len = 2;
5688c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_write(run, vcpu, val, (u16)res);
5698c2ecf20Sopenharmony_ci		break;
5708c2ecf20Sopenharmony_ci	case iocsrwrw_op:
5718c2ecf20Sopenharmony_ci		run->mmio.len = 4;
5728c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_write(run, vcpu, val, (u32)res);
5738c2ecf20Sopenharmony_ci		break;
5748c2ecf20Sopenharmony_ci	case iocsrwrd_op:
5758c2ecf20Sopenharmony_ci		run->mmio.len = 8;
5768c2ecf20Sopenharmony_ci		ret = _kvm_emu_iocsr_write(run, vcpu, val, res);
5778c2ecf20Sopenharmony_ci		break;
5788c2ecf20Sopenharmony_ci	default:
5798c2ecf20Sopenharmony_ci		ret = EMULATE_FAIL;
5808c2ecf20Sopenharmony_ci		break;
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (ret == EMULATE_DO_IOCSR) {
5848c2ecf20Sopenharmony_ci		vcpu->arch.io_gpr = rd;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	return ret;
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ciint _kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
5938c2ecf20Sopenharmony_ci	enum emulation_result er = EMULATE_DONE;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	switch (run->iocsr_io.len) {
5968c2ecf20Sopenharmony_ci	case 8:
5978c2ecf20Sopenharmony_ci		*gpr = *(s64 *)run->iocsr_io.data;
5988c2ecf20Sopenharmony_ci		break;
5998c2ecf20Sopenharmony_ci	case 4:
6008c2ecf20Sopenharmony_ci		*gpr = *(int *)run->iocsr_io.data;
6018c2ecf20Sopenharmony_ci		break;
6028c2ecf20Sopenharmony_ci	case 2:
6038c2ecf20Sopenharmony_ci		*gpr = *(short *)run->iocsr_io.data;
6048c2ecf20Sopenharmony_ci		break;
6058c2ecf20Sopenharmony_ci	case 1:
6068c2ecf20Sopenharmony_ci		*gpr = *(char *) run->iocsr_io.data;
6078c2ecf20Sopenharmony_ci		break;
6088c2ecf20Sopenharmony_ci	default:
6098c2ecf20Sopenharmony_ci		kvm_err("Bad IOCSR length: %d,addr is 0x%lx",
6108c2ecf20Sopenharmony_ci				run->iocsr_io.len, vcpu->arch.badv);
6118c2ecf20Sopenharmony_ci		er = EMULATE_FAIL;
6128c2ecf20Sopenharmony_ci		break;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return er;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ciint _kvm_get_iocsr(struct kvm *kvm, struct kvm_iocsr_entry *__user argp)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	struct kvm_iocsr_entry *entry, tmp;
6218c2ecf20Sopenharmony_ci	int r = -EFAULT;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (copy_from_user(&tmp, argp, sizeof(tmp)))
6248c2ecf20Sopenharmony_ci		goto out;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	spin_lock(&kvm->arch.iocsr_lock);
6278c2ecf20Sopenharmony_ci	entry = _kvm_find_iocsr(kvm, tmp.addr);
6288c2ecf20Sopenharmony_ci	if (entry != NULL)
6298c2ecf20Sopenharmony_ci		tmp.data = entry->data;
6308c2ecf20Sopenharmony_ci	spin_unlock(&kvm->arch.iocsr_lock);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (entry)
6338c2ecf20Sopenharmony_ci		r = copy_to_user(argp, &tmp, sizeof(tmp));
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ciout:
6368c2ecf20Sopenharmony_ci	return r;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ciint _kvm_set_iocsr(struct kvm *kvm, struct kvm_iocsr_entry *__user argp)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct kvm_iocsr_entry *entry, tmp;
6428c2ecf20Sopenharmony_ci	int r = -EFAULT;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	if (copy_from_user(&tmp, argp, sizeof(tmp)))
6458c2ecf20Sopenharmony_ci		goto out;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	spin_lock(&kvm->arch.iocsr_lock);
6488c2ecf20Sopenharmony_ci	entry = _kvm_find_iocsr(kvm, tmp.addr);
6498c2ecf20Sopenharmony_ci	if (entry != NULL) {
6508c2ecf20Sopenharmony_ci		r = 0;
6518c2ecf20Sopenharmony_ci		entry->data = tmp.data;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci	spin_unlock(&kvm->arch.iocsr_lock);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ciout:
6568c2ecf20Sopenharmony_ci	return r;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic struct kvm_iocsr_entry iocsr_array[IOCSR_MAX] = {
6608c2ecf20Sopenharmony_ci	{KVM_IOCSR_FEATURES, .data = KVM_IOCSRF_NODECNT|KVM_IOCSRF_MSI
6618c2ecf20Sopenharmony_ci				|KVM_IOCSRF_EXTIOI|KVM_IOCSRF_CSRIPI|KVM_IOCSRF_VM},
6628c2ecf20Sopenharmony_ci	{KVM_IOCSR_VENDOR, .data = 0x6e6f73676e6f6f4c}, /* Loongson */
6638c2ecf20Sopenharmony_ci	{KVM_IOCSR_CPUNAME, .data = 0x303030354133},	/* 3A5000 */
6648c2ecf20Sopenharmony_ci	{KVM_IOCSR_NODECNT, .data = 0x4},
6658c2ecf20Sopenharmony_ci	{KVM_IOCSR_MISC_FUNC, .data = 0x0},
6668c2ecf20Sopenharmony_ci};
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ciint _kvm_init_iocsr(struct kvm *kvm)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	int i = 0;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	spin_lock_init(&kvm->arch.iocsr_lock);
6738c2ecf20Sopenharmony_ci	for (i = 0; i < IOCSR_MAX; i++) {
6748c2ecf20Sopenharmony_ci		kvm->arch.iocsr[i].addr = iocsr_array[i].addr;
6758c2ecf20Sopenharmony_ci		kvm->arch.iocsr[i].data = iocsr_array[i].data;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci	return 0;
6788c2ecf20Sopenharmony_ci}
679