Merge tag 'kvm-arm-for-4-7-take2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / virt / kvm / arm / hyp / vgic-v2-sr.c
1 /*
2  * Copyright (C) 2012-2015 - ARM Ltd
3  * Author: Marc Zyngier <marc.zyngier@arm.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <linux/compiler.h>
19 #include <linux/irqchip/arm-gic.h>
20 #include <linux/kvm_host.h>
21
22 #include <asm/kvm_hyp.h>
23
24 #ifdef CONFIG_KVM_NEW_VGIC
25 extern struct vgic_global kvm_vgic_global_state;
26 #define vgic_v2_params kvm_vgic_global_state
27 #else
28 extern struct vgic_params vgic_v2_params;
29 #endif
30
31 static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
32                                             void __iomem *base)
33 {
34         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
35         int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
36         u32 eisr0, eisr1;
37         int i;
38         bool expect_mi;
39
40         expect_mi = !!(cpu_if->vgic_hcr & GICH_HCR_UIE);
41
42         for (i = 0; i < nr_lr; i++) {
43                 if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
44                                 continue;
45
46                 expect_mi |= (!(cpu_if->vgic_lr[i] & GICH_LR_HW) &&
47                               (cpu_if->vgic_lr[i] & GICH_LR_EOI));
48         }
49
50         if (expect_mi) {
51                 cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
52
53                 if (cpu_if->vgic_misr & GICH_MISR_EOI) {
54                         eisr0  = readl_relaxed(base + GICH_EISR0);
55                         if (unlikely(nr_lr > 32))
56                                 eisr1  = readl_relaxed(base + GICH_EISR1);
57                         else
58                                 eisr1 = 0;
59                 } else {
60                         eisr0 = eisr1 = 0;
61                 }
62         } else {
63                 cpu_if->vgic_misr = 0;
64                 eisr0 = eisr1 = 0;
65         }
66
67 #ifdef CONFIG_CPU_BIG_ENDIAN
68         cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
69 #else
70         cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
71 #endif
72 }
73
74 static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
75 {
76         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
77         int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
78         u32 elrsr0, elrsr1;
79
80         elrsr0 = readl_relaxed(base + GICH_ELRSR0);
81         if (unlikely(nr_lr > 32))
82                 elrsr1 = readl_relaxed(base + GICH_ELRSR1);
83         else
84                 elrsr1 = 0;
85
86 #ifdef CONFIG_CPU_BIG_ENDIAN
87         cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
88 #else
89         cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
90 #endif
91 }
92
93 static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
94 {
95         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
96         int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
97         int i;
98
99         for (i = 0; i < nr_lr; i++) {
100                 if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
101                         continue;
102
103                 if (cpu_if->vgic_elrsr & (1UL << i)) {
104                         cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
105                         continue;
106                 }
107
108                 cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
109                 writel_relaxed(0, base + GICH_LR0 + (i * 4));
110         }
111 }
112
113 /* vcpu is already in the HYP VA space */
114 void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
115 {
116         struct kvm *kvm = kern_hyp_va(vcpu->kvm);
117         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
118         struct vgic_dist *vgic = &kvm->arch.vgic;
119         void __iomem *base = kern_hyp_va(vgic->vctrl_base);
120
121         if (!base)
122                 return;
123
124         cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
125
126         if (vcpu->arch.vgic_cpu.live_lrs) {
127                 cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
128
129                 save_maint_int_state(vcpu, base);
130                 save_elrsr(vcpu, base);
131                 save_lrs(vcpu, base);
132
133                 writel_relaxed(0, base + GICH_HCR);
134
135                 vcpu->arch.vgic_cpu.live_lrs = 0;
136         } else {
137                 cpu_if->vgic_eisr = 0;
138                 cpu_if->vgic_elrsr = ~0UL;
139                 cpu_if->vgic_misr = 0;
140                 cpu_if->vgic_apr = 0;
141         }
142 }
143
144 /* vcpu is already in the HYP VA space */
145 void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
146 {
147         struct kvm *kvm = kern_hyp_va(vcpu->kvm);
148         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
149         struct vgic_dist *vgic = &kvm->arch.vgic;
150         void __iomem *base = kern_hyp_va(vgic->vctrl_base);
151         int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
152         int i;
153         u64 live_lrs = 0;
154
155         if (!base)
156                 return;
157
158
159         for (i = 0; i < nr_lr; i++)
160                 if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
161                         live_lrs |= 1UL << i;
162
163         if (live_lrs) {
164                 writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
165                 writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
166                 for (i = 0; i < nr_lr; i++) {
167                         if (!(live_lrs & (1UL << i)))
168                                 continue;
169
170                         writel_relaxed(cpu_if->vgic_lr[i],
171                                        base + GICH_LR0 + (i * 4));
172                 }
173         }
174
175         writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
176         vcpu->arch.vgic_cpu.live_lrs = live_lrs;
177 }