1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4 */
5
6#include <linux/errno.h>
7#include <linux/err.h>
8#include <linux/vmalloc.h>
9#include <linux/fs.h>
10#include <asm/page.h>
11#include <asm/cacheflush.h>
12#include "kvmcpu.h"
13#include <linux/kvm_host.h>
14#include "kvm_compat.h"
15
16static u32 int_to_coreint[LOONGARCH_EXC_MAX] = {
17	[LARCH_INT_TIMER]	= CPU_TIMER,
18	[LARCH_INT_IPI]		= CPU_IPI,
19	[LARCH_INT_SIP0]	= CPU_SIP0,
20	[LARCH_INT_SIP1]	= CPU_SIP1,
21	[LARCH_INT_IP0]		= CPU_IP0,
22	[LARCH_INT_IP1]		= CPU_IP1,
23	[LARCH_INT_IP2]		= CPU_IP2,
24	[LARCH_INT_IP3]		= CPU_IP3,
25	[LARCH_INT_IP4]		= CPU_IP4,
26	[LARCH_INT_IP5]		= CPU_IP5,
27	[LARCH_INT_IP6]		= CPU_IP6,
28	[LARCH_INT_IP7]		= CPU_IP7,
29};
30
31static int _kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
32{
33	unsigned int irq = 0;
34
35	clear_bit(priority, &vcpu->arch.irq_pending);
36	if (priority < LOONGARCH_EXC_MAX)
37		irq = int_to_coreint[priority];
38
39	switch (priority) {
40	case LARCH_INT_TIMER:
41	case LARCH_INT_IPI:
42	case LARCH_INT_SIP0:
43	case LARCH_INT_SIP1:
44		kvm_set_gcsr_estat(irq);
45		break;
46
47	case LARCH_INT_IP0:
48	case LARCH_INT_IP1:
49	case LARCH_INT_IP2:
50	case LARCH_INT_IP3:
51	case LARCH_INT_IP4:
52	case LARCH_INT_IP5:
53	case LARCH_INT_IP6:
54	case LARCH_INT_IP7:
55		kvm_set_csr_gintc(irq);
56		break;
57
58	default:
59		break;
60	}
61
62	return 1;
63}
64
65static int _kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
66{
67	unsigned int irq = 0;
68
69	clear_bit(priority, &vcpu->arch.irq_clear);
70	if (priority < LOONGARCH_EXC_MAX)
71		irq = int_to_coreint[priority];
72
73	switch (priority) {
74	case LARCH_INT_TIMER:
75	case LARCH_INT_IPI:
76	case LARCH_INT_SIP0:
77	case LARCH_INT_SIP1:
78		kvm_clear_gcsr_estat(irq);
79		break;
80
81	case LARCH_INT_IP0:
82	case LARCH_INT_IP1:
83	case LARCH_INT_IP2:
84	case LARCH_INT_IP3:
85	case LARCH_INT_IP4:
86	case LARCH_INT_IP5:
87	case LARCH_INT_IP6:
88	case LARCH_INT_IP7:
89		kvm_clear_csr_gintc(irq);
90		break;
91
92	default:
93		break;
94	}
95
96	return 1;
97}
98
99void _kvm_deliver_intr(struct kvm_vcpu *vcpu)
100{
101	unsigned long *pending = &vcpu->arch.irq_pending;
102	unsigned long *pending_clr = &vcpu->arch.irq_clear;
103	unsigned int priority;
104
105	if (!(*pending) && !(*pending_clr))
106		return;
107
108	if (*pending_clr) {
109		priority = __ffs(*pending_clr);
110		while (priority <= LOONGARCH_EXC_IPNUM) {
111			_kvm_irq_clear(vcpu, priority);
112			priority = find_next_bit(pending_clr,
113					BITS_PER_BYTE * sizeof(*pending_clr),
114					priority + 1);
115		}
116	}
117
118	if (*pending) {
119		priority = __ffs(*pending);
120		while (priority <= LOONGARCH_EXC_IPNUM) {
121			_kvm_irq_deliver(vcpu, priority);
122			priority = find_next_bit(pending,
123					BITS_PER_BYTE * sizeof(*pending),
124					priority + 1);
125		}
126	}
127
128}
129
130int _kvm_pending_timer(struct kvm_vcpu *vcpu)
131{
132	return test_bit(LARCH_INT_TIMER, &vcpu->arch.irq_pending);
133}
134