~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/virt/kvm/arm/hyp/vgic-v2-sr.c

Version: ~ [ linux-5.13-rc1 ] ~ [ linux-5.12.2 ] ~ [ linux-5.11.19 ] ~ [ linux-5.10.35 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.117 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 25                                             void __iomem *base)
 26 {
 27         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
 28         int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
 29         u32 eisr0, eisr1;
 30         int i;
 31         bool expect_mi;
 32 
 33         expect_mi = !!(cpu_if->vgic_hcr & GICH_HCR_UIE);
 34 
 35         for (i = 0; i < nr_lr; i++) {
 36                 if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
 37                                 continue;
 38 
 39                 expect_mi |= (!(cpu_if->vgic_lr[i] & GICH_LR_HW) &&
 40                               (cpu_if->vgic_lr[i] & GICH_LR_EOI));
 41         }
 42 
 43         if (expect_mi) {
 44                 cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
 45 
 46                 if (cpu_if->vgic_misr & GICH_MISR_EOI) {
 47                         eisr0  = readl_relaxed(base + GICH_EISR0);
 48                         if (unlikely(nr_lr > 32))
 49                                 eisr1  = readl_relaxed(base + GICH_EISR1);
 50                         else
 51                                 eisr1 = 0;
 52                 } else {
 53                         eisr0 = eisr1 = 0;
 54                 }
 55         } else {
 56                 cpu_if->vgic_misr = 0;
 57                 eisr0 = eisr1 = 0;
 58         }
 59 
 60 #ifdef CONFIG_CPU_BIG_ENDIAN
 61         cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
 62 #else
 63         cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
 64 #endif
 65 }
 66 
 67 static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
 68 {
 69         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
 70         int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
 71         u32 elrsr0, elrsr1;
 72 
 73         elrsr0 = readl_relaxed(base + GICH_ELRSR0);
 74         if (unlikely(nr_lr > 32))
 75                 elrsr1 = readl_relaxed(base + GICH_ELRSR1);
 76         else
 77                 elrsr1 = 0;
 78 
 79 #ifdef CONFIG_CPU_BIG_ENDIAN
 80         cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
 81 #else
 82         cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
 83 #endif
 84 }
 85 
 86 static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
 87 {
 88         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
 89         int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
 90         int i;
 91 
 92         for (i = 0; i < nr_lr; i++) {
 93                 if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
 94                         continue;
 95 
 96                 if (cpu_if->vgic_elrsr & (1UL << i))
 97                         cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
 98                 else
 99                         cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
100 
101                 writel_relaxed(0, base + GICH_LR0 + (i * 4));
102         }
103 }
104 
105 /* vcpu is already in the HYP VA space */
106 void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
107 {
108         struct kvm *kvm = kern_hyp_va(vcpu->kvm);
109         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
110         struct vgic_dist *vgic = &kvm->arch.vgic;
111         void __iomem *base = kern_hyp_va(vgic->vctrl_base);
112 
113         if (!base)
114                 return;
115 
116         cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
117 
118         if (vcpu->arch.vgic_cpu.live_lrs) {
119                 cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
120 
121                 save_maint_int_state(vcpu, base);
122                 save_elrsr(vcpu, base);
123                 save_lrs(vcpu, base);
124 
125                 writel_relaxed(0, base + GICH_HCR);
126 
127                 vcpu->arch.vgic_cpu.live_lrs = 0;
128         } else {
129                 cpu_if->vgic_eisr = 0;
130                 cpu_if->vgic_elrsr = ~0UL;
131                 cpu_if->vgic_misr = 0;
132                 cpu_if->vgic_apr = 0;
133         }
134 }
135 
136 /* vcpu is already in the HYP VA space */
137 void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
138 {
139         struct kvm *kvm = kern_hyp_va(vcpu->kvm);
140         struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
141         struct vgic_dist *vgic = &kvm->arch.vgic;
142         void __iomem *base = kern_hyp_va(vgic->vctrl_base);
143         int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
144         int i;
145         u64 live_lrs = 0;
146 
147         if (!base)
148                 return;
149 
150 
151         for (i = 0; i < nr_lr; i++)
152                 if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
153                         live_lrs |= 1UL << i;
154 
155         if (live_lrs) {
156                 writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
157                 writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
158                 for (i = 0; i < nr_lr; i++) {
159                         if (!(live_lrs & (1UL << i)))
160                                 continue;
161 
162                         writel_relaxed(cpu_if->vgic_lr[i],
163                                        base + GICH_LR0 + (i * 4));
164                 }
165         }
166 
167         writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
168         vcpu->arch.vgic_cpu.live_lrs = live_lrs;
169 }
170 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp