KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
[cascardo/linux.git] / virt / kvm / arm / vgic / vgic-v3.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License version 2 as
4  * published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program. If not, see <http://www.gnu.org/licenses/>.
13  */
14
15 #include <linux/irqchip/arm-gic-v3.h>
16 #include <linux/kvm.h>
17 #include <linux/kvm_host.h>
18
19 #include "vgic.h"
20
21 void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
22 {
23         struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
24         u32 model = vcpu->kvm->arch.vgic.vgic_model;
25
26         if (cpuif->vgic_misr & ICH_MISR_EOI) {
27                 unsigned long eisr_bmap = cpuif->vgic_eisr;
28                 int lr;
29
30                 for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
31                         u32 intid;
32                         u64 val = cpuif->vgic_lr[lr];
33
34                         if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
35                                 intid = val & ICH_LR_VIRTUAL_ID_MASK;
36                         else
37                                 intid = val & GICH_LR_VIRTUALID;
38
39                         WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
40
41                         kvm_notify_acked_irq(vcpu->kvm, 0,
42                                              intid - VGIC_NR_PRIVATE_IRQS);
43                 }
44
45                 /*
46                  * In the next iterations of the vcpu loop, if we sync
47                  * the vgic state after flushing it, but before
48                  * entering the guest (this happens for pending
49                  * signals and vmid rollovers), then make sure we
50                  * don't pick up any old maintenance interrupts here.
51                  */
52                 cpuif->vgic_eisr = 0;
53         }
54
55         cpuif->vgic_hcr &= ~ICH_HCR_UIE;
56 }
57
58 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
59 {
60         struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
61
62         cpuif->vgic_hcr |= ICH_HCR_UIE;
63 }
64
65 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
66 {
67         struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
68         u32 model = vcpu->kvm->arch.vgic.vgic_model;
69         int lr;
70
71         for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
72                 u64 val = cpuif->vgic_lr[lr];
73                 u32 intid;
74                 struct vgic_irq *irq;
75
76                 if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
77                         intid = val & ICH_LR_VIRTUAL_ID_MASK;
78                 else
79                         intid = val & GICH_LR_VIRTUALID;
80                 irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
81
82                 spin_lock(&irq->irq_lock);
83
84                 /* Always preserve the active bit */
85                 irq->active = !!(val & ICH_LR_ACTIVE_BIT);
86
87                 /* Edge is the only case where we preserve the pending bit */
88                 if (irq->config == VGIC_CONFIG_EDGE &&
89                     (val & ICH_LR_PENDING_BIT)) {
90                         irq->pending = true;
91
92                         if (vgic_irq_is_sgi(intid) &&
93                             model == KVM_DEV_TYPE_ARM_VGIC_V2) {
94                                 u32 cpuid = val & GICH_LR_PHYSID_CPUID;
95
96                                 cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
97                                 irq->source |= (1 << cpuid);
98                         }
99                 }
100
101                 /* Clear soft pending state when level irqs have been acked */
102                 if (irq->config == VGIC_CONFIG_LEVEL &&
103                     !(val & ICH_LR_PENDING_BIT)) {
104                         irq->soft_pending = false;
105                         irq->pending = irq->line_level;
106                 }
107
108                 spin_unlock(&irq->irq_lock);
109         }
110 }
111
112 /* Requires the irq to be locked already */
113 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
114 {
115         u32 model = vcpu->kvm->arch.vgic.vgic_model;
116         u64 val = irq->intid;
117
118         if (irq->pending) {
119                 val |= ICH_LR_PENDING_BIT;
120
121                 if (irq->config == VGIC_CONFIG_EDGE)
122                         irq->pending = false;
123
124                 if (vgic_irq_is_sgi(irq->intid) &&
125                     model == KVM_DEV_TYPE_ARM_VGIC_V2) {
126                         u32 src = ffs(irq->source);
127
128                         BUG_ON(!src);
129                         val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
130                         irq->source &= ~(1 << (src - 1));
131                         if (irq->source)
132                                 irq->pending = true;
133                 }
134         }
135
136         if (irq->active)
137                 val |= ICH_LR_ACTIVE_BIT;
138
139         if (irq->hw) {
140                 val |= ICH_LR_HW;
141                 val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
142         } else {
143                 if (irq->config == VGIC_CONFIG_LEVEL)
144                         val |= ICH_LR_EOI;
145         }
146
147         /*
148          * We currently only support Group1 interrupts, which is a
149          * known defect. This needs to be addressed at some point.
150          */
151         if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
152                 val |= ICH_LR_GROUP;
153
154         val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
155
156         vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
157 }
158
159 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
160 {
161         vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
162 }