aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kvm/coproc_a15.c
diff options
context:
space:
mode:
authorJonathan Austin <jonathan.austin@arm.com>2013-09-26 11:49:28 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2013-10-12 20:45:30 -0400
commite8c2d99f8277d68d28a9f99d16289712bc2aee7f (patch)
tree26f87c5f4aa7f952fb9b3e4ad28894556cee06b5 /arch/arm/kvm/coproc_a15.c
parent5e497046f005528464f9600a4ee04f49df713596 (diff)
KVM: ARM: Add support for Cortex-A7
This patch adds support for running Cortex-A7 guests on Cortex-A7 hosts. As Cortex-A7 is architecturally compatible with A15, this patch is largely just generalising existing code. Areas where 'implementation defined' behaviour is identical for A7 and A15 is moved to allow it to be used by both cores. The check to ensure that coprocessor register tables are sorted correctly is also moved in to 'common' code to avoid each new cpu doing its own check (and possibly forgetting to do so!) Signed-off-by: Jonathan Austin <jonathan.austin@arm.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'arch/arm/kvm/coproc_a15.c')
-rw-r--r--arch/arm/kvm/coproc_a15.c114
1 files changed, 1 insertions, 113 deletions
diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c
index bbd4b888dbf3..bb0cac1410cc 100644
--- a/arch/arm/kvm/coproc_a15.c
+++ b/arch/arm/kvm/coproc_a15.c
@@ -17,98 +17,12 @@
17 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */ 18 */
19#include <linux/kvm_host.h> 19#include <linux/kvm_host.h>
20#include <asm/cputype.h>
21#include <asm/kvm_arm.h>
22#include <asm/kvm_host.h>
23#include <asm/kvm_emulate.h>
24#include <asm/kvm_coproc.h> 20#include <asm/kvm_coproc.h>
21#include <asm/kvm_emulate.h>
25#include <linux/init.h> 22#include <linux/init.h>
26 23
27static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
28{
29 /*
30 * Compute guest MPIDR. No need to mess around with different clusters
31 * but we read the 'U' bit from the underlying hardware directly.
32 */
33 vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & MPIDR_SMP_BITMASK)
34 | vcpu->vcpu_id;
35}
36
37#include "coproc.h" 24#include "coproc.h"
38 25
39/* A15 TRM 4.3.28: RO WI */
40static bool access_actlr(struct kvm_vcpu *vcpu,
41 const struct coproc_params *p,
42 const struct coproc_reg *r)
43{
44 if (p->is_write)
45 return ignore_write(vcpu, p);
46
47 *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR];
48 return true;
49}
50
51/* A15 TRM 4.3.60: R/O. */
52static bool access_cbar(struct kvm_vcpu *vcpu,
53 const struct coproc_params *p,
54 const struct coproc_reg *r)
55{
56 if (p->is_write)
57 return write_to_read_only(vcpu, p);
58 return read_zero(vcpu, p);
59}
60
61/* A15 TRM 4.3.48: R/O WI. */
62static bool access_l2ctlr(struct kvm_vcpu *vcpu,
63 const struct coproc_params *p,
64 const struct coproc_reg *r)
65{
66 if (p->is_write)
67 return ignore_write(vcpu, p);
68
69 *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR];
70 return true;
71}
72
73static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
74{
75 u32 l2ctlr, ncores;
76
77 asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
78 l2ctlr &= ~(3 << 24);
79 ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1;
80 l2ctlr |= (ncores & 3) << 24;
81
82 vcpu->arch.cp15[c9_L2CTLR] = l2ctlr;
83}
84
85static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
86{
87 u32 actlr;
88
89 /* ACTLR contains SMP bit: make sure you create all cpus first! */
90 asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
91 /* Make the SMP bit consistent with the guest configuration */
92 if (atomic_read(&vcpu->kvm->online_vcpus) > 1)
93 actlr |= 1U << 6;
94 else
95 actlr &= ~(1U << 6);
96
97 vcpu->arch.cp15[c1_ACTLR] = actlr;
98}
99
100/* A15 TRM 4.3.49: R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored). */
101static bool access_l2ectlr(struct kvm_vcpu *vcpu,
102 const struct coproc_params *p,
103 const struct coproc_reg *r)
104{
105 if (p->is_write)
106 return ignore_write(vcpu, p);
107
108 *vcpu_reg(vcpu, p->Rt1) = 0;
109 return true;
110}
111
112/* 26/*
113 * A15-specific CP15 registers. 27 * A15-specific CP15 registers.
114 * CRn denotes the primary register number, but is copied to the CRm in the 28 * CRn denotes the primary register number, but is copied to the CRm in the
@@ -118,29 +32,9 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
118 * registers preceding 32-bit ones. 32 * registers preceding 32-bit ones.
119 */ 33 */
120static const struct coproc_reg a15_regs[] = { 34static const struct coproc_reg a15_regs[] = {
121 /* MPIDR: we use VMPIDR for guest access. */
122 { CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32,
123 NULL, reset_mpidr, c0_MPIDR },
124
125 /* SCTLR: swapped by interrupt.S. */ 35 /* SCTLR: swapped by interrupt.S. */
126 { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, 36 { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
127 NULL, reset_val, c1_SCTLR, 0x00C50078 }, 37 NULL, reset_val, c1_SCTLR, 0x00C50078 },
128 /* ACTLR: trapped by HCR.TAC bit. */
129 { CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32,
130 access_actlr, reset_actlr, c1_ACTLR },
131 /* CPACR: swapped by interrupt.S. */
132 { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
133 NULL, reset_val, c1_CPACR, 0x00000000 },
134
135 /*
136 * L2CTLR access (guest wants to know #CPUs).
137 */
138 { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32,
139 access_l2ctlr, reset_l2ctlr, c9_L2CTLR },
140 { CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr},
141
142 /* The Configuration Base Address Register. */
143 { CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar},
144}; 38};
145 39
146static struct kvm_coproc_target_table a15_target_table = { 40static struct kvm_coproc_target_table a15_target_table = {
@@ -151,12 +45,6 @@ static struct kvm_coproc_target_table a15_target_table = {
151 45
152static int __init coproc_a15_init(void) 46static int __init coproc_a15_init(void)
153{ 47{
154 unsigned int i;
155
156 for (i = 1; i < ARRAY_SIZE(a15_regs); i++)
157 BUG_ON(cmp_reg(&a15_regs[i-1],
158 &a15_regs[i]) >= 0);
159
160 kvm_register_target_coproc_table(&a15_target_table); 48 kvm_register_target_coproc_table(&a15_target_table);
161 return 0; 49 return 0;
162} 50}