diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-29 23:04:53 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-29 23:04:53 -0400 |
commit | 9ff9a26b786c35ee8d2a66222924a807ec851a9f (patch) | |
tree | db432a17bccca1ca2c16907f0ee83ac449ed4012 /arch/powerpc | |
parent | 0a3108beea9143225119d5e7c72a8e2c64f3eb7d (diff) | |
parent | 0d34fb8e93ceba7b6dad0062dbb4a0813bacd75b (diff) |
Merge commit 'origin/master' into next
Manual merge of:
arch/powerpc/include/asm/elf.h
drivers/i2c/busses/i2c-mpc.c
Diffstat (limited to 'arch/powerpc')
36 files changed, 1907 insertions, 429 deletions
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts index 540ec3241f72..5fd1ad09bdf2 100644 --- a/arch/powerpc/boot/dts/canyonlands.dts +++ b/arch/powerpc/boot/dts/canyonlands.dts | |||
@@ -127,6 +127,13 @@ | |||
127 | dcr-reg = <0x010 0x002>; | 127 | dcr-reg = <0x010 0x002>; |
128 | }; | 128 | }; |
129 | 129 | ||
130 | CRYPTO: crypto@180000 { | ||
131 | compatible = "amcc,ppc460ex-crypto", "amcc,ppc4xx-crypto"; | ||
132 | reg = <4 0x00180000 0x80400>; | ||
133 | interrupt-parent = <&UIC0>; | ||
134 | interrupts = <0x1d 0x4>; | ||
135 | }; | ||
136 | |||
130 | MAL0: mcmal { | 137 | MAL0: mcmal { |
131 | compatible = "ibm,mcmal-460ex", "ibm,mcmal2"; | 138 | compatible = "ibm,mcmal-460ex", "ibm,mcmal2"; |
132 | dcr-reg = <0x180 0x062>; | 139 | dcr-reg = <0x180 0x062>; |
diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts index 2804444812e5..5e6b08ff6f67 100644 --- a/arch/powerpc/boot/dts/kilauea.dts +++ b/arch/powerpc/boot/dts/kilauea.dts | |||
@@ -97,6 +97,13 @@ | |||
97 | 0x6 0x4>; /* ECC SEC Error */ | 97 | 0x6 0x4>; /* ECC SEC Error */ |
98 | }; | 98 | }; |
99 | 99 | ||
100 | CRYPTO: crypto@ef700000 { | ||
101 | compatible = "amcc,ppc405ex-crypto", "amcc,ppc4xx-crypto"; | ||
102 | reg = <0xef700000 0x80400>; | ||
103 | interrupt-parent = <&UIC0>; | ||
104 | interrupts = <0x17 0x2>; | ||
105 | }; | ||
106 | |||
100 | MAL0: mcmal { | 107 | MAL0: mcmal { |
101 | compatible = "ibm,mcmal-405ex", "ibm,mcmal2"; | 108 | compatible = "ibm,mcmal-405ex", "ibm,mcmal2"; |
102 | dcr-reg = <0x180 0x062>; | 109 | dcr-reg = <0x180 0x062>; |
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h index 4e0cf65f7f5a..bb2de6aa5ce0 100644 --- a/arch/powerpc/include/asm/kvm.h +++ b/arch/powerpc/include/asm/kvm.h | |||
@@ -52,4 +52,11 @@ struct kvm_fpu { | |||
52 | __u64 fpr[32]; | 52 | __u64 fpr[32]; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | struct kvm_debug_exit_arch { | ||
56 | }; | ||
57 | |||
58 | /* for KVM_SET_GUEST_DEBUG */ | ||
59 | struct kvm_guest_debug_arch { | ||
60 | }; | ||
61 | |||
55 | #endif /* __LINUX_KVM_POWERPC_H */ | 62 | #endif /* __LINUX_KVM_POWERPC_H */ |
diff --git a/arch/powerpc/include/asm/kvm_44x.h b/arch/powerpc/include/asm/kvm_44x.h index f49031b632ca..d22d39942a92 100644 --- a/arch/powerpc/include/asm/kvm_44x.h +++ b/arch/powerpc/include/asm/kvm_44x.h | |||
@@ -28,6 +28,13 @@ | |||
28 | * need to find some way of advertising it. */ | 28 | * need to find some way of advertising it. */ |
29 | #define KVM44x_GUEST_TLB_SIZE 64 | 29 | #define KVM44x_GUEST_TLB_SIZE 64 |
30 | 30 | ||
31 | struct kvmppc_44x_tlbe { | ||
32 | u32 tid; /* Only the low 8 bits are used. */ | ||
33 | u32 word0; | ||
34 | u32 word1; | ||
35 | u32 word2; | ||
36 | }; | ||
37 | |||
31 | struct kvmppc_44x_shadow_ref { | 38 | struct kvmppc_44x_shadow_ref { |
32 | struct page *page; | 39 | struct page *page; |
33 | u16 gtlb_index; | 40 | u16 gtlb_index; |
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 2197764796d9..56bfae59837f 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h | |||
@@ -42,7 +42,12 @@ | |||
42 | #define BOOKE_INTERRUPT_DTLB_MISS 13 | 42 | #define BOOKE_INTERRUPT_DTLB_MISS 13 |
43 | #define BOOKE_INTERRUPT_ITLB_MISS 14 | 43 | #define BOOKE_INTERRUPT_ITLB_MISS 14 |
44 | #define BOOKE_INTERRUPT_DEBUG 15 | 44 | #define BOOKE_INTERRUPT_DEBUG 15 |
45 | #define BOOKE_MAX_INTERRUPT 15 | 45 | |
46 | /* E500 */ | ||
47 | #define BOOKE_INTERRUPT_SPE_UNAVAIL 32 | ||
48 | #define BOOKE_INTERRUPT_SPE_FP_DATA 33 | ||
49 | #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 | ||
50 | #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 | ||
46 | 51 | ||
47 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ | 52 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ |
48 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ | 53 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ |
diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h new file mode 100644 index 000000000000..9d497ce49726 --- /dev/null +++ b/arch/powerpc/include/asm/kvm_e500.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: Yu Liu, <yu.liu@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * This file is derived from arch/powerpc/include/asm/kvm_44x.h, | ||
8 | * by Hollis Blanchard <hollisb@us.ibm.com>. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License, version 2, as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __ASM_KVM_E500_H__ | ||
16 | #define __ASM_KVM_E500_H__ | ||
17 | |||
18 | #include <linux/kvm_host.h> | ||
19 | |||
20 | #define BOOKE_INTERRUPT_SIZE 36 | ||
21 | |||
22 | #define E500_PID_NUM 3 | ||
23 | #define E500_TLB_NUM 2 | ||
24 | |||
25 | struct tlbe{ | ||
26 | u32 mas1; | ||
27 | u32 mas2; | ||
28 | u32 mas3; | ||
29 | u32 mas7; | ||
30 | }; | ||
31 | |||
32 | struct kvmppc_vcpu_e500 { | ||
33 | /* Unmodified copy of the guest's TLB. */ | ||
34 | struct tlbe *guest_tlb[E500_TLB_NUM]; | ||
35 | /* TLB that's actually used when the guest is running. */ | ||
36 | struct tlbe *shadow_tlb[E500_TLB_NUM]; | ||
37 | /* Pages which are referenced in the shadow TLB. */ | ||
38 | struct page **shadow_pages[E500_TLB_NUM]; | ||
39 | |||
40 | unsigned int guest_tlb_size[E500_TLB_NUM]; | ||
41 | unsigned int shadow_tlb_size[E500_TLB_NUM]; | ||
42 | unsigned int guest_tlb_nv[E500_TLB_NUM]; | ||
43 | |||
44 | u32 host_pid[E500_PID_NUM]; | ||
45 | u32 pid[E500_PID_NUM]; | ||
46 | |||
47 | u32 mas0; | ||
48 | u32 mas1; | ||
49 | u32 mas2; | ||
50 | u32 mas3; | ||
51 | u32 mas4; | ||
52 | u32 mas5; | ||
53 | u32 mas6; | ||
54 | u32 mas7; | ||
55 | u32 l1csr1; | ||
56 | u32 hid0; | ||
57 | u32 hid1; | ||
58 | |||
59 | struct kvm_vcpu vcpu; | ||
60 | }; | ||
61 | |||
62 | static inline struct kvmppc_vcpu_e500 *to_e500(struct kvm_vcpu *vcpu) | ||
63 | { | ||
64 | return container_of(vcpu, struct kvmppc_vcpu_e500, vcpu); | ||
65 | } | ||
66 | |||
67 | #endif /* __ASM_KVM_E500_H__ */ | ||
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index c1e436fe7738..dfdf13c9fefd 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -64,13 +64,6 @@ struct kvm_vcpu_stat { | |||
64 | u32 halt_wakeup; | 64 | u32 halt_wakeup; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct kvmppc_44x_tlbe { | ||
68 | u32 tid; /* Only the low 8 bits are used. */ | ||
69 | u32 word0; | ||
70 | u32 word1; | ||
71 | u32 word2; | ||
72 | }; | ||
73 | |||
74 | enum kvm_exit_types { | 67 | enum kvm_exit_types { |
75 | MMIO_EXITS, | 68 | MMIO_EXITS, |
76 | DCR_EXITS, | 69 | DCR_EXITS, |
@@ -118,11 +111,6 @@ struct kvm_arch { | |||
118 | struct kvm_vcpu_arch { | 111 | struct kvm_vcpu_arch { |
119 | u32 host_stack; | 112 | u32 host_stack; |
120 | u32 host_pid; | 113 | u32 host_pid; |
121 | u32 host_dbcr0; | ||
122 | u32 host_dbcr1; | ||
123 | u32 host_dbcr2; | ||
124 | u32 host_iac[4]; | ||
125 | u32 host_msr; | ||
126 | 114 | ||
127 | u64 fpr[32]; | 115 | u64 fpr[32]; |
128 | ulong gpr[32]; | 116 | ulong gpr[32]; |
@@ -157,7 +145,7 @@ struct kvm_vcpu_arch { | |||
157 | u32 tbu; | 145 | u32 tbu; |
158 | u32 tcr; | 146 | u32 tcr; |
159 | u32 tsr; | 147 | u32 tsr; |
160 | u32 ivor[16]; | 148 | u32 ivor[64]; |
161 | ulong ivpr; | 149 | ulong ivpr; |
162 | u32 pir; | 150 | u32 pir; |
163 | 151 | ||
@@ -170,6 +158,7 @@ struct kvm_vcpu_arch { | |||
170 | u32 ccr1; | 158 | u32 ccr1; |
171 | u32 dbcr0; | 159 | u32 dbcr0; |
172 | u32 dbcr1; | 160 | u32 dbcr1; |
161 | u32 dbsr; | ||
173 | 162 | ||
174 | #ifdef CONFIG_KVM_EXIT_TIMING | 163 | #ifdef CONFIG_KVM_EXIT_TIMING |
175 | struct kvmppc_exit_timing timing_exit; | 164 | struct kvmppc_exit_timing timing_exit; |
@@ -200,10 +189,4 @@ struct kvm_vcpu_arch { | |||
200 | unsigned long pending_exceptions; | 189 | unsigned long pending_exceptions; |
201 | }; | 190 | }; |
202 | 191 | ||
203 | struct kvm_guest_debug { | ||
204 | int enabled; | ||
205 | unsigned long bp[4]; | ||
206 | int singlestep; | ||
207 | }; | ||
208 | |||
209 | #endif /* __POWERPC_KVM_HOST_H__ */ | 192 | #endif /* __POWERPC_KVM_HOST_H__ */ |
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 36d2a50a8487..2c6ee349df5e 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h | |||
@@ -52,13 +52,19 @@ extern int kvmppc_emulate_instruction(struct kvm_run *run, | |||
52 | extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu); | 52 | extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu); |
53 | extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu); | 53 | extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu); |
54 | 54 | ||
55 | /* Core-specific hooks */ | ||
56 | |||
55 | extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, | 57 | extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, |
56 | u64 asid, u32 flags, u32 max_bytes, | ||
57 | unsigned int gtlb_idx); | 58 | unsigned int gtlb_idx); |
58 | extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode); | 59 | extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode); |
59 | extern void kvmppc_mmu_switch_pid(struct kvm_vcpu *vcpu, u32 pid); | 60 | extern void kvmppc_mmu_switch_pid(struct kvm_vcpu *vcpu, u32 pid); |
60 | 61 | extern void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu); | |
61 | /* Core-specific hooks */ | 62 | extern int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr); |
63 | extern int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr); | ||
64 | extern gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index, | ||
65 | gva_t eaddr); | ||
66 | extern void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu); | ||
67 | extern void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu); | ||
62 | 68 | ||
63 | extern struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, | 69 | extern struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, |
64 | unsigned int id); | 70 | unsigned int id); |
@@ -71,9 +77,6 @@ extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, | |||
71 | extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu); | 77 | extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu); |
72 | extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu); | 78 | extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu); |
73 | 79 | ||
74 | extern void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu); | ||
75 | extern void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu); | ||
76 | |||
77 | extern void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu); | 80 | extern void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu); |
78 | extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu); | 81 | extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu); |
79 | extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu); | 82 | extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu); |
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index c5363c3a7207..7e74cff81d86 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h | |||
@@ -93,6 +93,8 @@ | |||
93 | 93 | ||
94 | #ifndef __ASSEMBLY__ | 94 | #ifndef __ASSEMBLY__ |
95 | 95 | ||
96 | extern unsigned int tlbcam_index; | ||
97 | |||
96 | typedef struct { | 98 | typedef struct { |
97 | unsigned int id; | 99 | unsigned int id; |
98 | unsigned int active; | 100 | unsigned int active; |
diff --git a/arch/powerpc/include/asm/ps3fb.h b/arch/powerpc/include/asm/ps3fb.h index 1a91daf362c8..90dbefb8cfc4 100644 --- a/arch/powerpc/include/asm/ps3fb.h +++ b/arch/powerpc/include/asm/ps3fb.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #ifndef _ASM_POWERPC_PS3FB_H_ | 19 | #ifndef _ASM_POWERPC_PS3FB_H_ |
20 | #define _ASM_POWERPC_PS3FB_H_ | 20 | #define _ASM_POWERPC_PS3FB_H_ |
21 | 21 | ||
22 | #include <linux/types.h> | ||
22 | #include <linux/ioctl.h> | 23 | #include <linux/ioctl.h> |
23 | #include <linux/types.h> | 24 | #include <linux/types.h> |
24 | 25 | ||
diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index f5a4e168e498..1e5cfad0e3f7 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h | |||
@@ -61,4 +61,7 @@ | |||
61 | 61 | ||
62 | #define SO_MARK 36 | 62 | #define SO_MARK 36 |
63 | 63 | ||
64 | #define SO_TIMESTAMPING 37 | ||
65 | #define SCM_TIMESTAMPING SO_TIMESTAMPING | ||
66 | |||
64 | #endif /* _ASM_POWERPC_SOCKET_H */ | 67 | #endif /* _ASM_POWERPC_SOCKET_H */ |
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 72353f6070a4..fe166491e9dc 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h | |||
@@ -65,7 +65,7 @@ SYSCALL(ni_syscall) | |||
65 | SYSX(sys_ni_syscall,sys_olduname, sys_olduname) | 65 | SYSX(sys_ni_syscall,sys_olduname, sys_olduname) |
66 | COMPAT_SYS_SPU(umask) | 66 | COMPAT_SYS_SPU(umask) |
67 | SYSCALL_SPU(chroot) | 67 | SYSCALL_SPU(chroot) |
68 | SYSCALL(ustat) | 68 | COMPAT_SYS(ustat) |
69 | SYSCALL_SPU(dup2) | 69 | SYSCALL_SPU(dup2) |
70 | SYSCALL_SPU(getppid) | 70 | SYSCALL_SPU(getppid) |
71 | SYSCALL_SPU(getpgrp) | 71 | SYSCALL_SPU(getpgrp) |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 10377df38f36..1e40bc053946 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -49,7 +49,7 @@ | |||
49 | #include <asm/iseries/alpaca.h> | 49 | #include <asm/iseries/alpaca.h> |
50 | #endif | 50 | #endif |
51 | #ifdef CONFIG_KVM | 51 | #ifdef CONFIG_KVM |
52 | #include <asm/kvm_44x.h> | 52 | #include <linux/kvm_host.h> |
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | 55 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) |
@@ -358,8 +358,6 @@ int main(void) | |||
358 | DEFINE(PTE_SIZE, sizeof(pte_t)); | 358 | DEFINE(PTE_SIZE, sizeof(pte_t)); |
359 | 359 | ||
360 | #ifdef CONFIG_KVM | 360 | #ifdef CONFIG_KVM |
361 | DEFINE(TLBE_BYTES, sizeof(struct kvmppc_44x_tlbe)); | ||
362 | |||
363 | DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); | 361 | DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); |
364 | DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); | 362 | DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); |
365 | DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); | 363 | DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 48ea2008b20d..5576147e57b6 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -190,7 +190,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
190 | seq_printf(p, "%3d: ", i); | 190 | seq_printf(p, "%3d: ", i); |
191 | #ifdef CONFIG_SMP | 191 | #ifdef CONFIG_SMP |
192 | for_each_online_cpu(j) | 192 | for_each_online_cpu(j) |
193 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 193 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); |
194 | #else | 194 | #else |
195 | seq_printf(p, "%10u ", kstat_irqs(i)); | 195 | seq_printf(p, "%10u ", kstat_irqs(i)); |
196 | #endif /* CONFIG_SMP */ | 196 | #endif /* CONFIG_SMP */ |
@@ -231,7 +231,7 @@ void fixup_irqs(cpumask_t map) | |||
231 | if (irq_desc[irq].status & IRQ_PER_CPU) | 231 | if (irq_desc[irq].status & IRQ_PER_CPU) |
232 | continue; | 232 | continue; |
233 | 233 | ||
234 | cpus_and(mask, irq_desc[irq].affinity, map); | 234 | cpumask_and(&mask, irq_desc[irq].affinity, &map); |
235 | if (any_online_cpu(mask) == NR_CPUS) { | 235 | if (any_online_cpu(mask) == NR_CPUS) { |
236 | printk("Breaking affinity for irq %i\n", irq); | 236 | printk("Breaking affinity for irq %i\n", irq); |
237 | mask = map; | 237 | mask = map; |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 895af44bf1f4..b9ef1644a722 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -182,13 +182,7 @@ SECTIONS | |||
182 | __initramfs_end = .; | 182 | __initramfs_end = .; |
183 | } | 183 | } |
184 | #endif | 184 | #endif |
185 | . = ALIGN(PAGE_SIZE); | 185 | PERCPU(PAGE_SIZE) |
186 | .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { | ||
187 | __per_cpu_start = .; | ||
188 | *(.data.percpu) | ||
189 | *(.data.percpu.shared_aligned) | ||
190 | __per_cpu_end = .; | ||
191 | } | ||
192 | 186 | ||
193 | . = ALIGN(8); | 187 | . = ALIGN(8); |
194 | .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) { | 188 | .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) { |
diff --git a/arch/powerpc/kvm/44x.c b/arch/powerpc/kvm/44x.c index a66bec57265a..0cef809cec21 100644 --- a/arch/powerpc/kvm/44x.c +++ b/arch/powerpc/kvm/44x.c | |||
@@ -28,72 +28,6 @@ | |||
28 | 28 | ||
29 | #include "44x_tlb.h" | 29 | #include "44x_tlb.h" |
30 | 30 | ||
31 | /* Note: clearing MSR[DE] just means that the debug interrupt will not be | ||
32 | * delivered *immediately*. Instead, it simply sets the appropriate DBSR bits. | ||
33 | * If those DBSR bits are still set when MSR[DE] is re-enabled, the interrupt | ||
34 | * will be delivered as an "imprecise debug event" (which is indicated by | ||
35 | * DBSR[IDE]. | ||
36 | */ | ||
37 | static void kvm44x_disable_debug_interrupts(void) | ||
38 | { | ||
39 | mtmsr(mfmsr() & ~MSR_DE); | ||
40 | } | ||
41 | |||
42 | void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) | ||
43 | { | ||
44 | kvm44x_disable_debug_interrupts(); | ||
45 | |||
46 | mtspr(SPRN_IAC1, vcpu->arch.host_iac[0]); | ||
47 | mtspr(SPRN_IAC2, vcpu->arch.host_iac[1]); | ||
48 | mtspr(SPRN_IAC3, vcpu->arch.host_iac[2]); | ||
49 | mtspr(SPRN_IAC4, vcpu->arch.host_iac[3]); | ||
50 | mtspr(SPRN_DBCR1, vcpu->arch.host_dbcr1); | ||
51 | mtspr(SPRN_DBCR2, vcpu->arch.host_dbcr2); | ||
52 | mtspr(SPRN_DBCR0, vcpu->arch.host_dbcr0); | ||
53 | mtmsr(vcpu->arch.host_msr); | ||
54 | } | ||
55 | |||
56 | void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) | ||
57 | { | ||
58 | struct kvm_guest_debug *dbg = &vcpu->guest_debug; | ||
59 | u32 dbcr0 = 0; | ||
60 | |||
61 | vcpu->arch.host_msr = mfmsr(); | ||
62 | kvm44x_disable_debug_interrupts(); | ||
63 | |||
64 | /* Save host debug register state. */ | ||
65 | vcpu->arch.host_iac[0] = mfspr(SPRN_IAC1); | ||
66 | vcpu->arch.host_iac[1] = mfspr(SPRN_IAC2); | ||
67 | vcpu->arch.host_iac[2] = mfspr(SPRN_IAC3); | ||
68 | vcpu->arch.host_iac[3] = mfspr(SPRN_IAC4); | ||
69 | vcpu->arch.host_dbcr0 = mfspr(SPRN_DBCR0); | ||
70 | vcpu->arch.host_dbcr1 = mfspr(SPRN_DBCR1); | ||
71 | vcpu->arch.host_dbcr2 = mfspr(SPRN_DBCR2); | ||
72 | |||
73 | /* set registers up for guest */ | ||
74 | |||
75 | if (dbg->bp[0]) { | ||
76 | mtspr(SPRN_IAC1, dbg->bp[0]); | ||
77 | dbcr0 |= DBCR0_IAC1 | DBCR0_IDM; | ||
78 | } | ||
79 | if (dbg->bp[1]) { | ||
80 | mtspr(SPRN_IAC2, dbg->bp[1]); | ||
81 | dbcr0 |= DBCR0_IAC2 | DBCR0_IDM; | ||
82 | } | ||
83 | if (dbg->bp[2]) { | ||
84 | mtspr(SPRN_IAC3, dbg->bp[2]); | ||
85 | dbcr0 |= DBCR0_IAC3 | DBCR0_IDM; | ||
86 | } | ||
87 | if (dbg->bp[3]) { | ||
88 | mtspr(SPRN_IAC4, dbg->bp[3]); | ||
89 | dbcr0 |= DBCR0_IAC4 | DBCR0_IDM; | ||
90 | } | ||
91 | |||
92 | mtspr(SPRN_DBCR0, dbcr0); | ||
93 | mtspr(SPRN_DBCR1, 0); | ||
94 | mtspr(SPRN_DBCR2, 0); | ||
95 | } | ||
96 | |||
97 | void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | 31 | void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) |
98 | { | 32 | { |
99 | kvmppc_44x_tlb_load(vcpu); | 33 | kvmppc_44x_tlb_load(vcpu); |
@@ -149,8 +83,6 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu) | |||
149 | int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, | 83 | int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, |
150 | struct kvm_translation *tr) | 84 | struct kvm_translation *tr) |
151 | { | 85 | { |
152 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); | ||
153 | struct kvmppc_44x_tlbe *gtlbe; | ||
154 | int index; | 86 | int index; |
155 | gva_t eaddr; | 87 | gva_t eaddr; |
156 | u8 pid; | 88 | u8 pid; |
@@ -166,9 +98,7 @@ int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, | |||
166 | return 0; | 98 | return 0; |
167 | } | 99 | } |
168 | 100 | ||
169 | gtlbe = &vcpu_44x->guest_tlb[index]; | 101 | tr->physical_address = kvmppc_mmu_xlate(vcpu, index, eaddr); |
170 | |||
171 | tr->physical_address = tlb_xlate(gtlbe, eaddr); | ||
172 | /* XXX what does "writeable" and "usermode" even mean? */ | 102 | /* XXX what does "writeable" and "usermode" even mean? */ |
173 | tr->valid = 1; | 103 | tr->valid = 1; |
174 | 104 | ||
diff --git a/arch/powerpc/kvm/44x_emulate.c b/arch/powerpc/kvm/44x_emulate.c index 82489a743a6f..61af58fcecee 100644 --- a/arch/powerpc/kvm/44x_emulate.c +++ b/arch/powerpc/kvm/44x_emulate.c | |||
@@ -27,25 +27,12 @@ | |||
27 | #include "booke.h" | 27 | #include "booke.h" |
28 | #include "44x_tlb.h" | 28 | #include "44x_tlb.h" |
29 | 29 | ||
30 | #define OP_RFI 19 | ||
31 | |||
32 | #define XOP_RFI 50 | ||
33 | #define XOP_MFMSR 83 | ||
34 | #define XOP_WRTEE 131 | ||
35 | #define XOP_MTMSR 146 | ||
36 | #define XOP_WRTEEI 163 | ||
37 | #define XOP_MFDCR 323 | 30 | #define XOP_MFDCR 323 |
38 | #define XOP_MTDCR 451 | 31 | #define XOP_MTDCR 451 |
39 | #define XOP_TLBSX 914 | 32 | #define XOP_TLBSX 914 |
40 | #define XOP_ICCCI 966 | 33 | #define XOP_ICCCI 966 |
41 | #define XOP_TLBWE 978 | 34 | #define XOP_TLBWE 978 |
42 | 35 | ||
43 | static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu) | ||
44 | { | ||
45 | vcpu->arch.pc = vcpu->arch.srr0; | ||
46 | kvmppc_set_msr(vcpu, vcpu->arch.srr1); | ||
47 | } | ||
48 | |||
49 | int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | 36 | int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, |
50 | unsigned int inst, int *advance) | 37 | unsigned int inst, int *advance) |
51 | { | 38 | { |
@@ -59,48 +46,9 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
59 | int ws; | 46 | int ws; |
60 | 47 | ||
61 | switch (get_op(inst)) { | 48 | switch (get_op(inst)) { |
62 | case OP_RFI: | ||
63 | switch (get_xop(inst)) { | ||
64 | case XOP_RFI: | ||
65 | kvmppc_emul_rfi(vcpu); | ||
66 | kvmppc_set_exit_type(vcpu, EMULATED_RFI_EXITS); | ||
67 | *advance = 0; | ||
68 | break; | ||
69 | |||
70 | default: | ||
71 | emulated = EMULATE_FAIL; | ||
72 | break; | ||
73 | } | ||
74 | break; | ||
75 | |||
76 | case 31: | 49 | case 31: |
77 | switch (get_xop(inst)) { | 50 | switch (get_xop(inst)) { |
78 | 51 | ||
79 | case XOP_MFMSR: | ||
80 | rt = get_rt(inst); | ||
81 | vcpu->arch.gpr[rt] = vcpu->arch.msr; | ||
82 | kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS); | ||
83 | break; | ||
84 | |||
85 | case XOP_MTMSR: | ||
86 | rs = get_rs(inst); | ||
87 | kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS); | ||
88 | kvmppc_set_msr(vcpu, vcpu->arch.gpr[rs]); | ||
89 | break; | ||
90 | |||
91 | case XOP_WRTEE: | ||
92 | rs = get_rs(inst); | ||
93 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | ||
94 | | (vcpu->arch.gpr[rs] & MSR_EE); | ||
95 | kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); | ||
96 | break; | ||
97 | |||
98 | case XOP_WRTEEI: | ||
99 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | ||
100 | | (inst & MSR_EE); | ||
101 | kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); | ||
102 | break; | ||
103 | |||
104 | case XOP_MFDCR: | 52 | case XOP_MFDCR: |
105 | dcrn = get_dcrn(inst); | 53 | dcrn = get_dcrn(inst); |
106 | rt = get_rt(inst); | 54 | rt = get_rt(inst); |
@@ -186,186 +134,51 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
186 | emulated = EMULATE_FAIL; | 134 | emulated = EMULATE_FAIL; |
187 | } | 135 | } |
188 | 136 | ||
137 | if (emulated == EMULATE_FAIL) | ||
138 | emulated = kvmppc_booke_emulate_op(run, vcpu, inst, advance); | ||
139 | |||
189 | return emulated; | 140 | return emulated; |
190 | } | 141 | } |
191 | 142 | ||
192 | int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | 143 | int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) |
193 | { | 144 | { |
145 | int emulated = EMULATE_DONE; | ||
146 | |||
194 | switch (sprn) { | 147 | switch (sprn) { |
195 | case SPRN_MMUCR: | ||
196 | vcpu->arch.mmucr = vcpu->arch.gpr[rs]; break; | ||
197 | case SPRN_PID: | 148 | case SPRN_PID: |
198 | kvmppc_set_pid(vcpu, vcpu->arch.gpr[rs]); break; | 149 | kvmppc_set_pid(vcpu, vcpu->arch.gpr[rs]); break; |
150 | case SPRN_MMUCR: | ||
151 | vcpu->arch.mmucr = vcpu->arch.gpr[rs]; break; | ||
199 | case SPRN_CCR0: | 152 | case SPRN_CCR0: |
200 | vcpu->arch.ccr0 = vcpu->arch.gpr[rs]; break; | 153 | vcpu->arch.ccr0 = vcpu->arch.gpr[rs]; break; |
201 | case SPRN_CCR1: | 154 | case SPRN_CCR1: |
202 | vcpu->arch.ccr1 = vcpu->arch.gpr[rs]; break; | 155 | vcpu->arch.ccr1 = vcpu->arch.gpr[rs]; break; |
203 | case SPRN_DEAR: | ||
204 | vcpu->arch.dear = vcpu->arch.gpr[rs]; break; | ||
205 | case SPRN_ESR: | ||
206 | vcpu->arch.esr = vcpu->arch.gpr[rs]; break; | ||
207 | case SPRN_DBCR0: | ||
208 | vcpu->arch.dbcr0 = vcpu->arch.gpr[rs]; break; | ||
209 | case SPRN_DBCR1: | ||
210 | vcpu->arch.dbcr1 = vcpu->arch.gpr[rs]; break; | ||
211 | case SPRN_TSR: | ||
212 | vcpu->arch.tsr &= ~vcpu->arch.gpr[rs]; break; | ||
213 | case SPRN_TCR: | ||
214 | vcpu->arch.tcr = vcpu->arch.gpr[rs]; | ||
215 | kvmppc_emulate_dec(vcpu); | ||
216 | break; | ||
217 | |||
218 | /* Note: SPRG4-7 are user-readable. These values are | ||
219 | * loaded into the real SPRGs when resuming the | ||
220 | * guest. */ | ||
221 | case SPRN_SPRG4: | ||
222 | vcpu->arch.sprg4 = vcpu->arch.gpr[rs]; break; | ||
223 | case SPRN_SPRG5: | ||
224 | vcpu->arch.sprg5 = vcpu->arch.gpr[rs]; break; | ||
225 | case SPRN_SPRG6: | ||
226 | vcpu->arch.sprg6 = vcpu->arch.gpr[rs]; break; | ||
227 | case SPRN_SPRG7: | ||
228 | vcpu->arch.sprg7 = vcpu->arch.gpr[rs]; break; | ||
229 | |||
230 | case SPRN_IVPR: | ||
231 | vcpu->arch.ivpr = vcpu->arch.gpr[rs]; | ||
232 | break; | ||
233 | case SPRN_IVOR0: | ||
234 | vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] = vcpu->arch.gpr[rs]; | ||
235 | break; | ||
236 | case SPRN_IVOR1: | ||
237 | vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK] = vcpu->arch.gpr[rs]; | ||
238 | break; | ||
239 | case SPRN_IVOR2: | ||
240 | vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] = vcpu->arch.gpr[rs]; | ||
241 | break; | ||
242 | case SPRN_IVOR3: | ||
243 | vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] = vcpu->arch.gpr[rs]; | ||
244 | break; | ||
245 | case SPRN_IVOR4: | ||
246 | vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL] = vcpu->arch.gpr[rs]; | ||
247 | break; | ||
248 | case SPRN_IVOR5: | ||
249 | vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT] = vcpu->arch.gpr[rs]; | ||
250 | break; | ||
251 | case SPRN_IVOR6: | ||
252 | vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM] = vcpu->arch.gpr[rs]; | ||
253 | break; | ||
254 | case SPRN_IVOR7: | ||
255 | vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL] = vcpu->arch.gpr[rs]; | ||
256 | break; | ||
257 | case SPRN_IVOR8: | ||
258 | vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL] = vcpu->arch.gpr[rs]; | ||
259 | break; | ||
260 | case SPRN_IVOR9: | ||
261 | vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] = vcpu->arch.gpr[rs]; | ||
262 | break; | ||
263 | case SPRN_IVOR10: | ||
264 | vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER] = vcpu->arch.gpr[rs]; | ||
265 | break; | ||
266 | case SPRN_IVOR11: | ||
267 | vcpu->arch.ivor[BOOKE_IRQPRIO_FIT] = vcpu->arch.gpr[rs]; | ||
268 | break; | ||
269 | case SPRN_IVOR12: | ||
270 | vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG] = vcpu->arch.gpr[rs]; | ||
271 | break; | ||
272 | case SPRN_IVOR13: | ||
273 | vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS] = vcpu->arch.gpr[rs]; | ||
274 | break; | ||
275 | case SPRN_IVOR14: | ||
276 | vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS] = vcpu->arch.gpr[rs]; | ||
277 | break; | ||
278 | case SPRN_IVOR15: | ||
279 | vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = vcpu->arch.gpr[rs]; | ||
280 | break; | ||
281 | |||
282 | default: | 156 | default: |
283 | return EMULATE_FAIL; | 157 | emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, rs); |
284 | } | 158 | } |
285 | 159 | ||
286 | kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS); | 160 | kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS); |
287 | return EMULATE_DONE; | 161 | return emulated; |
288 | } | 162 | } |
289 | 163 | ||
290 | int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | 164 | int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) |
291 | { | 165 | { |
166 | int emulated = EMULATE_DONE; | ||
167 | |||
292 | switch (sprn) { | 168 | switch (sprn) { |
293 | /* 440 */ | 169 | case SPRN_PID: |
170 | vcpu->arch.gpr[rt] = vcpu->arch.pid; break; | ||
294 | case SPRN_MMUCR: | 171 | case SPRN_MMUCR: |
295 | vcpu->arch.gpr[rt] = vcpu->arch.mmucr; break; | 172 | vcpu->arch.gpr[rt] = vcpu->arch.mmucr; break; |
296 | case SPRN_CCR0: | 173 | case SPRN_CCR0: |
297 | vcpu->arch.gpr[rt] = vcpu->arch.ccr0; break; | 174 | vcpu->arch.gpr[rt] = vcpu->arch.ccr0; break; |
298 | case SPRN_CCR1: | 175 | case SPRN_CCR1: |
299 | vcpu->arch.gpr[rt] = vcpu->arch.ccr1; break; | 176 | vcpu->arch.gpr[rt] = vcpu->arch.ccr1; break; |
300 | |||
301 | /* Book E */ | ||
302 | case SPRN_PID: | ||
303 | vcpu->arch.gpr[rt] = vcpu->arch.pid; break; | ||
304 | case SPRN_IVPR: | ||
305 | vcpu->arch.gpr[rt] = vcpu->arch.ivpr; break; | ||
306 | case SPRN_DEAR: | ||
307 | vcpu->arch.gpr[rt] = vcpu->arch.dear; break; | ||
308 | case SPRN_ESR: | ||
309 | vcpu->arch.gpr[rt] = vcpu->arch.esr; break; | ||
310 | case SPRN_DBCR0: | ||
311 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr0; break; | ||
312 | case SPRN_DBCR1: | ||
313 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr1; break; | ||
314 | |||
315 | case SPRN_IVOR0: | ||
316 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]; | ||
317 | break; | ||
318 | case SPRN_IVOR1: | ||
319 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK]; | ||
320 | break; | ||
321 | case SPRN_IVOR2: | ||
322 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]; | ||
323 | break; | ||
324 | case SPRN_IVOR3: | ||
325 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE]; | ||
326 | break; | ||
327 | case SPRN_IVOR4: | ||
328 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL]; | ||
329 | break; | ||
330 | case SPRN_IVOR5: | ||
331 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT]; | ||
332 | break; | ||
333 | case SPRN_IVOR6: | ||
334 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM]; | ||
335 | break; | ||
336 | case SPRN_IVOR7: | ||
337 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL]; | ||
338 | break; | ||
339 | case SPRN_IVOR8: | ||
340 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL]; | ||
341 | break; | ||
342 | case SPRN_IVOR9: | ||
343 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL]; | ||
344 | break; | ||
345 | case SPRN_IVOR10: | ||
346 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER]; | ||
347 | break; | ||
348 | case SPRN_IVOR11: | ||
349 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_FIT]; | ||
350 | break; | ||
351 | case SPRN_IVOR12: | ||
352 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG]; | ||
353 | break; | ||
354 | case SPRN_IVOR13: | ||
355 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS]; | ||
356 | break; | ||
357 | case SPRN_IVOR14: | ||
358 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS]; | ||
359 | break; | ||
360 | case SPRN_IVOR15: | ||
361 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG]; | ||
362 | break; | ||
363 | |||
364 | default: | 177 | default: |
365 | return EMULATE_FAIL; | 178 | emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, rt); |
366 | } | 179 | } |
367 | 180 | ||
368 | kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS); | 181 | kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS); |
369 | return EMULATE_DONE; | 182 | return emulated; |
370 | } | 183 | } |
371 | 184 | ||
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index 9a34b8edb9e2..4a16f472cc18 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c | |||
@@ -208,20 +208,38 @@ int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid, | |||
208 | return -1; | 208 | return -1; |
209 | } | 209 | } |
210 | 210 | ||
211 | int kvmppc_44x_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) | 211 | gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index, |
212 | gva_t eaddr) | ||
213 | { | ||
214 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); | ||
215 | struct kvmppc_44x_tlbe *gtlbe = &vcpu_44x->guest_tlb[gtlb_index]; | ||
216 | unsigned int pgmask = get_tlb_bytes(gtlbe) - 1; | ||
217 | |||
218 | return get_tlb_raddr(gtlbe) | (eaddr & pgmask); | ||
219 | } | ||
220 | |||
221 | int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) | ||
212 | { | 222 | { |
213 | unsigned int as = !!(vcpu->arch.msr & MSR_IS); | 223 | unsigned int as = !!(vcpu->arch.msr & MSR_IS); |
214 | 224 | ||
215 | return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); | 225 | return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); |
216 | } | 226 | } |
217 | 227 | ||
218 | int kvmppc_44x_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) | 228 | int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) |
219 | { | 229 | { |
220 | unsigned int as = !!(vcpu->arch.msr & MSR_DS); | 230 | unsigned int as = !!(vcpu->arch.msr & MSR_DS); |
221 | 231 | ||
222 | return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); | 232 | return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); |
223 | } | 233 | } |
224 | 234 | ||
235 | void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu) | ||
236 | { | ||
237 | } | ||
238 | |||
239 | void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu) | ||
240 | { | ||
241 | } | ||
242 | |||
225 | static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x, | 243 | static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x, |
226 | unsigned int stlb_index) | 244 | unsigned int stlb_index) |
227 | { | 245 | { |
@@ -248,7 +266,7 @@ static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x, | |||
248 | KVMTRACE_1D(STLB_INVAL, &vcpu_44x->vcpu, stlb_index, handler); | 266 | KVMTRACE_1D(STLB_INVAL, &vcpu_44x->vcpu, stlb_index, handler); |
249 | } | 267 | } |
250 | 268 | ||
251 | void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu) | 269 | void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) |
252 | { | 270 | { |
253 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); | 271 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); |
254 | int i; | 272 | int i; |
@@ -269,15 +287,19 @@ void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu) | |||
269 | * Caller must ensure that the specified guest TLB entry is safe to insert into | 287 | * Caller must ensure that the specified guest TLB entry is safe to insert into |
270 | * the shadow TLB. | 288 | * the shadow TLB. |
271 | */ | 289 | */ |
272 | void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, u64 asid, | 290 | void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, |
273 | u32 flags, u32 max_bytes, unsigned int gtlb_index) | 291 | unsigned int gtlb_index) |
274 | { | 292 | { |
275 | struct kvmppc_44x_tlbe stlbe; | 293 | struct kvmppc_44x_tlbe stlbe; |
276 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); | 294 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); |
295 | struct kvmppc_44x_tlbe *gtlbe = &vcpu_44x->guest_tlb[gtlb_index]; | ||
277 | struct kvmppc_44x_shadow_ref *ref; | 296 | struct kvmppc_44x_shadow_ref *ref; |
278 | struct page *new_page; | 297 | struct page *new_page; |
279 | hpa_t hpaddr; | 298 | hpa_t hpaddr; |
280 | gfn_t gfn; | 299 | gfn_t gfn; |
300 | u32 asid = gtlbe->tid; | ||
301 | u32 flags = gtlbe->word2; | ||
302 | u32 max_bytes = get_tlb_bytes(gtlbe); | ||
281 | unsigned int victim; | 303 | unsigned int victim; |
282 | 304 | ||
283 | /* Select TLB entry to clobber. Indirectly guard against races with the TLB | 305 | /* Select TLB entry to clobber. Indirectly guard against races with the TLB |
@@ -448,10 +470,8 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws) | |||
448 | } | 470 | } |
449 | 471 | ||
450 | if (tlbe_is_host_safe(vcpu, tlbe)) { | 472 | if (tlbe_is_host_safe(vcpu, tlbe)) { |
451 | u64 asid; | ||
452 | gva_t eaddr; | 473 | gva_t eaddr; |
453 | gpa_t gpaddr; | 474 | gpa_t gpaddr; |
454 | u32 flags; | ||
455 | u32 bytes; | 475 | u32 bytes; |
456 | 476 | ||
457 | eaddr = get_tlb_eaddr(tlbe); | 477 | eaddr = get_tlb_eaddr(tlbe); |
@@ -462,10 +482,7 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws) | |||
462 | eaddr &= ~(bytes - 1); | 482 | eaddr &= ~(bytes - 1); |
463 | gpaddr &= ~(bytes - 1); | 483 | gpaddr &= ~(bytes - 1); |
464 | 484 | ||
465 | asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid; | 485 | kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlb_index); |
466 | flags = tlbe->word2 & 0xffff; | ||
467 | |||
468 | kvmppc_mmu_map(vcpu, eaddr, gpaddr, asid, flags, bytes, gtlb_index); | ||
469 | } | 486 | } |
470 | 487 | ||
471 | KVMTRACE_5D(GTLB_WRITE, vcpu, gtlb_index, tlbe->tid, tlbe->word0, | 488 | KVMTRACE_5D(GTLB_WRITE, vcpu, gtlb_index, tlbe->tid, tlbe->word0, |
diff --git a/arch/powerpc/kvm/44x_tlb.h b/arch/powerpc/kvm/44x_tlb.h index 772191f29e62..a9ff80e51526 100644 --- a/arch/powerpc/kvm/44x_tlb.h +++ b/arch/powerpc/kvm/44x_tlb.h | |||
@@ -25,8 +25,6 @@ | |||
25 | 25 | ||
26 | extern int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, | 26 | extern int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, |
27 | unsigned int pid, unsigned int as); | 27 | unsigned int pid, unsigned int as); |
28 | extern int kvmppc_44x_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr); | ||
29 | extern int kvmppc_44x_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr); | ||
30 | 28 | ||
31 | extern int kvmppc_44x_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb, | 29 | extern int kvmppc_44x_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb, |
32 | u8 rc); | 30 | u8 rc); |
@@ -85,11 +83,4 @@ static inline unsigned int get_mmucr_sts(const struct kvm_vcpu *vcpu) | |||
85 | return (vcpu->arch.mmucr >> 16) & 0x1; | 83 | return (vcpu->arch.mmucr >> 16) & 0x1; |
86 | } | 84 | } |
87 | 85 | ||
88 | static inline gpa_t tlb_xlate(struct kvmppc_44x_tlbe *tlbe, gva_t eaddr) | ||
89 | { | ||
90 | unsigned int pgmask = get_tlb_bytes(tlbe) - 1; | ||
91 | |||
92 | return get_tlb_raddr(tlbe) | (eaddr & pgmask); | ||
93 | } | ||
94 | |||
95 | #endif /* __KVM_POWERPC_TLB_H__ */ | 86 | #endif /* __KVM_POWERPC_TLB_H__ */ |
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 6dbdc4817d80..5a152a52796f 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig | |||
@@ -2,6 +2,9 @@ | |||
2 | # KVM configuration | 2 | # KVM configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | config HAVE_KVM_IRQCHIP | ||
6 | bool | ||
7 | |||
5 | menuconfig VIRTUALIZATION | 8 | menuconfig VIRTUALIZATION |
6 | bool "Virtualization" | 9 | bool "Virtualization" |
7 | ---help--- | 10 | ---help--- |
@@ -43,6 +46,19 @@ config KVM_EXIT_TIMING | |||
43 | 46 | ||
44 | If unsure, say N. | 47 | If unsure, say N. |
45 | 48 | ||
49 | config KVM_E500 | ||
50 | bool "KVM support for PowerPC E500 processors" | ||
51 | depends on EXPERIMENTAL && E500 | ||
52 | select KVM | ||
53 | ---help--- | ||
54 | Support running unmodified E500 guest kernels in virtual machines on | ||
55 | E500 host processors. | ||
56 | |||
57 | This module provides access to the hardware capabilities through | ||
58 | a character device node named /dev/kvm. | ||
59 | |||
60 | If unsure, say N. | ||
61 | |||
46 | config KVM_TRACE | 62 | config KVM_TRACE |
47 | bool "KVM trace support" | 63 | bool "KVM trace support" |
48 | depends on KVM && MARKERS && SYSFS | 64 | depends on KVM && MARKERS && SYSFS |
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index df7ba59e6d53..4b2df66c79d8 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile | |||
@@ -16,8 +16,18 @@ AFLAGS_booke_interrupts.o := -I$(obj) | |||
16 | 16 | ||
17 | kvm-440-objs := \ | 17 | kvm-440-objs := \ |
18 | booke.o \ | 18 | booke.o \ |
19 | booke_emulate.o \ | ||
19 | booke_interrupts.o \ | 20 | booke_interrupts.o \ |
20 | 44x.o \ | 21 | 44x.o \ |
21 | 44x_tlb.o \ | 22 | 44x_tlb.o \ |
22 | 44x_emulate.o | 23 | 44x_emulate.o |
23 | obj-$(CONFIG_KVM_440) += kvm-440.o | 24 | obj-$(CONFIG_KVM_440) += kvm-440.o |
25 | |||
26 | kvm-e500-objs := \ | ||
27 | booke.o \ | ||
28 | booke_emulate.o \ | ||
29 | booke_interrupts.o \ | ||
30 | e500.o \ | ||
31 | e500_tlb.o \ | ||
32 | e500_emulate.o | ||
33 | obj-$(CONFIG_KVM_E500) += kvm-e500.o | ||
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 35485dd6927e..642e4204cf25 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c | |||
@@ -30,10 +30,8 @@ | |||
30 | #include <asm/kvm_ppc.h> | 30 | #include <asm/kvm_ppc.h> |
31 | #include "timing.h" | 31 | #include "timing.h" |
32 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
33 | #include <asm/kvm_44x.h> | ||
34 | 33 | ||
35 | #include "booke.h" | 34 | #include "booke.h" |
36 | #include "44x_tlb.h" | ||
37 | 35 | ||
38 | unsigned long kvmppc_booke_handlers; | 36 | unsigned long kvmppc_booke_handlers; |
39 | 37 | ||
@@ -120,6 +118,9 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | |||
120 | case BOOKE_IRQPRIO_DATA_STORAGE: | 118 | case BOOKE_IRQPRIO_DATA_STORAGE: |
121 | case BOOKE_IRQPRIO_INST_STORAGE: | 119 | case BOOKE_IRQPRIO_INST_STORAGE: |
122 | case BOOKE_IRQPRIO_FP_UNAVAIL: | 120 | case BOOKE_IRQPRIO_FP_UNAVAIL: |
121 | case BOOKE_IRQPRIO_SPE_UNAVAIL: | ||
122 | case BOOKE_IRQPRIO_SPE_FP_DATA: | ||
123 | case BOOKE_IRQPRIO_SPE_FP_ROUND: | ||
123 | case BOOKE_IRQPRIO_AP_UNAVAIL: | 124 | case BOOKE_IRQPRIO_AP_UNAVAIL: |
124 | case BOOKE_IRQPRIO_ALIGNMENT: | 125 | case BOOKE_IRQPRIO_ALIGNMENT: |
125 | allowed = 1; | 126 | allowed = 1; |
@@ -165,7 +166,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | |||
165 | unsigned int priority; | 166 | unsigned int priority; |
166 | 167 | ||
167 | priority = __ffs(*pending); | 168 | priority = __ffs(*pending); |
168 | while (priority <= BOOKE_MAX_INTERRUPT) { | 169 | while (priority <= BOOKE_IRQPRIO_MAX) { |
169 | if (kvmppc_booke_irqprio_deliver(vcpu, priority)) | 170 | if (kvmppc_booke_irqprio_deliver(vcpu, priority)) |
170 | break; | 171 | break; |
171 | 172 | ||
@@ -263,6 +264,21 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
263 | r = RESUME_GUEST; | 264 | r = RESUME_GUEST; |
264 | break; | 265 | break; |
265 | 266 | ||
267 | case BOOKE_INTERRUPT_SPE_UNAVAIL: | ||
268 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_UNAVAIL); | ||
269 | r = RESUME_GUEST; | ||
270 | break; | ||
271 | |||
272 | case BOOKE_INTERRUPT_SPE_FP_DATA: | ||
273 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_DATA); | ||
274 | r = RESUME_GUEST; | ||
275 | break; | ||
276 | |||
277 | case BOOKE_INTERRUPT_SPE_FP_ROUND: | ||
278 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND); | ||
279 | r = RESUME_GUEST; | ||
280 | break; | ||
281 | |||
266 | case BOOKE_INTERRUPT_DATA_STORAGE: | 282 | case BOOKE_INTERRUPT_DATA_STORAGE: |
267 | vcpu->arch.dear = vcpu->arch.fault_dear; | 283 | vcpu->arch.dear = vcpu->arch.fault_dear; |
268 | vcpu->arch.esr = vcpu->arch.fault_esr; | 284 | vcpu->arch.esr = vcpu->arch.fault_esr; |
@@ -284,29 +300,27 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
284 | r = RESUME_GUEST; | 300 | r = RESUME_GUEST; |
285 | break; | 301 | break; |
286 | 302 | ||
287 | /* XXX move to a 440-specific file. */ | ||
288 | case BOOKE_INTERRUPT_DTLB_MISS: { | 303 | case BOOKE_INTERRUPT_DTLB_MISS: { |
289 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); | ||
290 | struct kvmppc_44x_tlbe *gtlbe; | ||
291 | unsigned long eaddr = vcpu->arch.fault_dear; | 304 | unsigned long eaddr = vcpu->arch.fault_dear; |
292 | int gtlb_index; | 305 | int gtlb_index; |
306 | gpa_t gpaddr; | ||
293 | gfn_t gfn; | 307 | gfn_t gfn; |
294 | 308 | ||
295 | /* Check the guest TLB. */ | 309 | /* Check the guest TLB. */ |
296 | gtlb_index = kvmppc_44x_dtlb_index(vcpu, eaddr); | 310 | gtlb_index = kvmppc_mmu_dtlb_index(vcpu, eaddr); |
297 | if (gtlb_index < 0) { | 311 | if (gtlb_index < 0) { |
298 | /* The guest didn't have a mapping for it. */ | 312 | /* The guest didn't have a mapping for it. */ |
299 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS); | 313 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS); |
300 | vcpu->arch.dear = vcpu->arch.fault_dear; | 314 | vcpu->arch.dear = vcpu->arch.fault_dear; |
301 | vcpu->arch.esr = vcpu->arch.fault_esr; | 315 | vcpu->arch.esr = vcpu->arch.fault_esr; |
316 | kvmppc_mmu_dtlb_miss(vcpu); | ||
302 | kvmppc_account_exit(vcpu, DTLB_REAL_MISS_EXITS); | 317 | kvmppc_account_exit(vcpu, DTLB_REAL_MISS_EXITS); |
303 | r = RESUME_GUEST; | 318 | r = RESUME_GUEST; |
304 | break; | 319 | break; |
305 | } | 320 | } |
306 | 321 | ||
307 | gtlbe = &vcpu_44x->guest_tlb[gtlb_index]; | 322 | gpaddr = kvmppc_mmu_xlate(vcpu, gtlb_index, eaddr); |
308 | vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr); | 323 | gfn = gpaddr >> PAGE_SHIFT; |
309 | gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT; | ||
310 | 324 | ||
311 | if (kvm_is_visible_gfn(vcpu->kvm, gfn)) { | 325 | if (kvm_is_visible_gfn(vcpu->kvm, gfn)) { |
312 | /* The guest TLB had a mapping, but the shadow TLB | 326 | /* The guest TLB had a mapping, but the shadow TLB |
@@ -315,13 +329,13 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
315 | * b) the guest used a large mapping which we're faking | 329 | * b) the guest used a large mapping which we're faking |
316 | * Either way, we need to satisfy the fault without | 330 | * Either way, we need to satisfy the fault without |
317 | * invoking the guest. */ | 331 | * invoking the guest. */ |
318 | kvmppc_mmu_map(vcpu, eaddr, vcpu->arch.paddr_accessed, gtlbe->tid, | 332 | kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlb_index); |
319 | gtlbe->word2, get_tlb_bytes(gtlbe), gtlb_index); | ||
320 | kvmppc_account_exit(vcpu, DTLB_VIRT_MISS_EXITS); | 333 | kvmppc_account_exit(vcpu, DTLB_VIRT_MISS_EXITS); |
321 | r = RESUME_GUEST; | 334 | r = RESUME_GUEST; |
322 | } else { | 335 | } else { |
323 | /* Guest has mapped and accessed a page which is not | 336 | /* Guest has mapped and accessed a page which is not |
324 | * actually RAM. */ | 337 | * actually RAM. */ |
338 | vcpu->arch.paddr_accessed = gpaddr; | ||
325 | r = kvmppc_emulate_mmio(run, vcpu); | 339 | r = kvmppc_emulate_mmio(run, vcpu); |
326 | kvmppc_account_exit(vcpu, MMIO_EXITS); | 340 | kvmppc_account_exit(vcpu, MMIO_EXITS); |
327 | } | 341 | } |
@@ -329,10 +343,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
329 | break; | 343 | break; |
330 | } | 344 | } |
331 | 345 | ||
332 | /* XXX move to a 440-specific file. */ | ||
333 | case BOOKE_INTERRUPT_ITLB_MISS: { | 346 | case BOOKE_INTERRUPT_ITLB_MISS: { |
334 | struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); | ||
335 | struct kvmppc_44x_tlbe *gtlbe; | ||
336 | unsigned long eaddr = vcpu->arch.pc; | 347 | unsigned long eaddr = vcpu->arch.pc; |
337 | gpa_t gpaddr; | 348 | gpa_t gpaddr; |
338 | gfn_t gfn; | 349 | gfn_t gfn; |
@@ -341,18 +352,18 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
341 | r = RESUME_GUEST; | 352 | r = RESUME_GUEST; |
342 | 353 | ||
343 | /* Check the guest TLB. */ | 354 | /* Check the guest TLB. */ |
344 | gtlb_index = kvmppc_44x_itlb_index(vcpu, eaddr); | 355 | gtlb_index = kvmppc_mmu_itlb_index(vcpu, eaddr); |
345 | if (gtlb_index < 0) { | 356 | if (gtlb_index < 0) { |
346 | /* The guest didn't have a mapping for it. */ | 357 | /* The guest didn't have a mapping for it. */ |
347 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ITLB_MISS); | 358 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ITLB_MISS); |
359 | kvmppc_mmu_itlb_miss(vcpu); | ||
348 | kvmppc_account_exit(vcpu, ITLB_REAL_MISS_EXITS); | 360 | kvmppc_account_exit(vcpu, ITLB_REAL_MISS_EXITS); |
349 | break; | 361 | break; |
350 | } | 362 | } |
351 | 363 | ||
352 | kvmppc_account_exit(vcpu, ITLB_VIRT_MISS_EXITS); | 364 | kvmppc_account_exit(vcpu, ITLB_VIRT_MISS_EXITS); |
353 | 365 | ||
354 | gtlbe = &vcpu_44x->guest_tlb[gtlb_index]; | 366 | gpaddr = kvmppc_mmu_xlate(vcpu, gtlb_index, eaddr); |
355 | gpaddr = tlb_xlate(gtlbe, eaddr); | ||
356 | gfn = gpaddr >> PAGE_SHIFT; | 367 | gfn = gpaddr >> PAGE_SHIFT; |
357 | 368 | ||
358 | if (kvm_is_visible_gfn(vcpu->kvm, gfn)) { | 369 | if (kvm_is_visible_gfn(vcpu->kvm, gfn)) { |
@@ -362,8 +373,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
362 | * b) the guest used a large mapping which we're faking | 373 | * b) the guest used a large mapping which we're faking |
363 | * Either way, we need to satisfy the fault without | 374 | * Either way, we need to satisfy the fault without |
364 | * invoking the guest. */ | 375 | * invoking the guest. */ |
365 | kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlbe->tid, | 376 | kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlb_index); |
366 | gtlbe->word2, get_tlb_bytes(gtlbe), gtlb_index); | ||
367 | } else { | 377 | } else { |
368 | /* Guest mapped and leaped at non-RAM! */ | 378 | /* Guest mapped and leaped at non-RAM! */ |
369 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_MACHINE_CHECK); | 379 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_MACHINE_CHECK); |
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index cf7c94ca24bf..d59bcca1f9d8 100644 --- a/arch/powerpc/kvm/booke.h +++ b/arch/powerpc/kvm/booke.h | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/kvm_host.h> | 24 | #include <linux/kvm_host.h> |
25 | #include <asm/kvm_ppc.h> | ||
25 | #include "timing.h" | 26 | #include "timing.h" |
26 | 27 | ||
27 | /* interrupt priortity ordering */ | 28 | /* interrupt priortity ordering */ |
@@ -30,17 +31,24 @@ | |||
30 | #define BOOKE_IRQPRIO_ALIGNMENT 2 | 31 | #define BOOKE_IRQPRIO_ALIGNMENT 2 |
31 | #define BOOKE_IRQPRIO_PROGRAM 3 | 32 | #define BOOKE_IRQPRIO_PROGRAM 3 |
32 | #define BOOKE_IRQPRIO_FP_UNAVAIL 4 | 33 | #define BOOKE_IRQPRIO_FP_UNAVAIL 4 |
33 | #define BOOKE_IRQPRIO_SYSCALL 5 | 34 | #define BOOKE_IRQPRIO_SPE_UNAVAIL 5 |
34 | #define BOOKE_IRQPRIO_AP_UNAVAIL 6 | 35 | #define BOOKE_IRQPRIO_SPE_FP_DATA 6 |
35 | #define BOOKE_IRQPRIO_DTLB_MISS 7 | 36 | #define BOOKE_IRQPRIO_SPE_FP_ROUND 7 |
36 | #define BOOKE_IRQPRIO_ITLB_MISS 8 | 37 | #define BOOKE_IRQPRIO_SYSCALL 8 |
37 | #define BOOKE_IRQPRIO_MACHINE_CHECK 9 | 38 | #define BOOKE_IRQPRIO_AP_UNAVAIL 9 |
38 | #define BOOKE_IRQPRIO_DEBUG 10 | 39 | #define BOOKE_IRQPRIO_DTLB_MISS 10 |
39 | #define BOOKE_IRQPRIO_CRITICAL 11 | 40 | #define BOOKE_IRQPRIO_ITLB_MISS 11 |
40 | #define BOOKE_IRQPRIO_WATCHDOG 12 | 41 | #define BOOKE_IRQPRIO_MACHINE_CHECK 12 |
41 | #define BOOKE_IRQPRIO_EXTERNAL 13 | 42 | #define BOOKE_IRQPRIO_DEBUG 13 |
42 | #define BOOKE_IRQPRIO_FIT 14 | 43 | #define BOOKE_IRQPRIO_CRITICAL 14 |
43 | #define BOOKE_IRQPRIO_DECREMENTER 15 | 44 | #define BOOKE_IRQPRIO_WATCHDOG 15 |
45 | #define BOOKE_IRQPRIO_EXTERNAL 16 | ||
46 | #define BOOKE_IRQPRIO_FIT 17 | ||
47 | #define BOOKE_IRQPRIO_DECREMENTER 18 | ||
48 | #define BOOKE_IRQPRIO_PERFORMANCE_MONITOR 19 | ||
49 | #define BOOKE_IRQPRIO_MAX 19 | ||
50 | |||
51 | extern unsigned long kvmppc_booke_handlers; | ||
44 | 52 | ||
45 | /* Helper function for "full" MSR writes. No need to call this if only EE is | 53 | /* Helper function for "full" MSR writes. No need to call this if only EE is |
46 | * changing. */ | 54 | * changing. */ |
@@ -57,4 +65,9 @@ static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr) | |||
57 | }; | 65 | }; |
58 | } | 66 | } |
59 | 67 | ||
68 | int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
69 | unsigned int inst, int *advance); | ||
70 | int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt); | ||
71 | int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs); | ||
72 | |||
60 | #endif /* __KVM_BOOKE_H__ */ | 73 | #endif /* __KVM_BOOKE_H__ */ |
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c new file mode 100644 index 000000000000..aebc65e93f4b --- /dev/null +++ b/arch/powerpc/kvm/booke_emulate.c | |||
@@ -0,0 +1,266 @@ | |||
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, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2008 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | */ | ||
19 | |||
20 | #include <linux/kvm_host.h> | ||
21 | #include <asm/disassemble.h> | ||
22 | |||
23 | #include "booke.h" | ||
24 | |||
25 | #define OP_19_XOP_RFI 50 | ||
26 | |||
27 | #define OP_31_XOP_MFMSR 83 | ||
28 | #define OP_31_XOP_WRTEE 131 | ||
29 | #define OP_31_XOP_MTMSR 146 | ||
30 | #define OP_31_XOP_WRTEEI 163 | ||
31 | |||
32 | static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu) | ||
33 | { | ||
34 | vcpu->arch.pc = vcpu->arch.srr0; | ||
35 | kvmppc_set_msr(vcpu, vcpu->arch.srr1); | ||
36 | } | ||
37 | |||
38 | int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
39 | unsigned int inst, int *advance) | ||
40 | { | ||
41 | int emulated = EMULATE_DONE; | ||
42 | int rs; | ||
43 | int rt; | ||
44 | |||
45 | switch (get_op(inst)) { | ||
46 | case 19: | ||
47 | switch (get_xop(inst)) { | ||
48 | case OP_19_XOP_RFI: | ||
49 | kvmppc_emul_rfi(vcpu); | ||
50 | kvmppc_set_exit_type(vcpu, EMULATED_RFI_EXITS); | ||
51 | *advance = 0; | ||
52 | break; | ||
53 | |||
54 | default: | ||
55 | emulated = EMULATE_FAIL; | ||
56 | break; | ||
57 | } | ||
58 | break; | ||
59 | |||
60 | case 31: | ||
61 | switch (get_xop(inst)) { | ||
62 | |||
63 | case OP_31_XOP_MFMSR: | ||
64 | rt = get_rt(inst); | ||
65 | vcpu->arch.gpr[rt] = vcpu->arch.msr; | ||
66 | kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS); | ||
67 | break; | ||
68 | |||
69 | case OP_31_XOP_MTMSR: | ||
70 | rs = get_rs(inst); | ||
71 | kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS); | ||
72 | kvmppc_set_msr(vcpu, vcpu->arch.gpr[rs]); | ||
73 | break; | ||
74 | |||
75 | case OP_31_XOP_WRTEE: | ||
76 | rs = get_rs(inst); | ||
77 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | ||
78 | | (vcpu->arch.gpr[rs] & MSR_EE); | ||
79 | kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); | ||
80 | break; | ||
81 | |||
82 | case OP_31_XOP_WRTEEI: | ||
83 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | ||
84 | | (inst & MSR_EE); | ||
85 | kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); | ||
86 | break; | ||
87 | |||
88 | default: | ||
89 | emulated = EMULATE_FAIL; | ||
90 | } | ||
91 | |||
92 | break; | ||
93 | |||
94 | default: | ||
95 | emulated = EMULATE_FAIL; | ||
96 | } | ||
97 | |||
98 | return emulated; | ||
99 | } | ||
100 | |||
101 | int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||
102 | { | ||
103 | int emulated = EMULATE_DONE; | ||
104 | |||
105 | switch (sprn) { | ||
106 | case SPRN_DEAR: | ||
107 | vcpu->arch.dear = vcpu->arch.gpr[rs]; break; | ||
108 | case SPRN_ESR: | ||
109 | vcpu->arch.esr = vcpu->arch.gpr[rs]; break; | ||
110 | case SPRN_DBCR0: | ||
111 | vcpu->arch.dbcr0 = vcpu->arch.gpr[rs]; break; | ||
112 | case SPRN_DBCR1: | ||
113 | vcpu->arch.dbcr1 = vcpu->arch.gpr[rs]; break; | ||
114 | case SPRN_DBSR: | ||
115 | vcpu->arch.dbsr &= ~vcpu->arch.gpr[rs]; break; | ||
116 | case SPRN_TSR: | ||
117 | vcpu->arch.tsr &= ~vcpu->arch.gpr[rs]; break; | ||
118 | case SPRN_TCR: | ||
119 | vcpu->arch.tcr = vcpu->arch.gpr[rs]; | ||
120 | kvmppc_emulate_dec(vcpu); | ||
121 | break; | ||
122 | |||
123 | /* Note: SPRG4-7 are user-readable. These values are | ||
124 | * loaded into the real SPRGs when resuming the | ||
125 | * guest. */ | ||
126 | case SPRN_SPRG4: | ||
127 | vcpu->arch.sprg4 = vcpu->arch.gpr[rs]; break; | ||
128 | case SPRN_SPRG5: | ||
129 | vcpu->arch.sprg5 = vcpu->arch.gpr[rs]; break; | ||
130 | case SPRN_SPRG6: | ||
131 | vcpu->arch.sprg6 = vcpu->arch.gpr[rs]; break; | ||
132 | case SPRN_SPRG7: | ||
133 | vcpu->arch.sprg7 = vcpu->arch.gpr[rs]; break; | ||
134 | |||
135 | case SPRN_IVPR: | ||
136 | vcpu->arch.ivpr = vcpu->arch.gpr[rs]; | ||
137 | break; | ||
138 | case SPRN_IVOR0: | ||
139 | vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] = vcpu->arch.gpr[rs]; | ||
140 | break; | ||
141 | case SPRN_IVOR1: | ||
142 | vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK] = vcpu->arch.gpr[rs]; | ||
143 | break; | ||
144 | case SPRN_IVOR2: | ||
145 | vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] = vcpu->arch.gpr[rs]; | ||
146 | break; | ||
147 | case SPRN_IVOR3: | ||
148 | vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] = vcpu->arch.gpr[rs]; | ||
149 | break; | ||
150 | case SPRN_IVOR4: | ||
151 | vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL] = vcpu->arch.gpr[rs]; | ||
152 | break; | ||
153 | case SPRN_IVOR5: | ||
154 | vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT] = vcpu->arch.gpr[rs]; | ||
155 | break; | ||
156 | case SPRN_IVOR6: | ||
157 | vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM] = vcpu->arch.gpr[rs]; | ||
158 | break; | ||
159 | case SPRN_IVOR7: | ||
160 | vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL] = vcpu->arch.gpr[rs]; | ||
161 | break; | ||
162 | case SPRN_IVOR8: | ||
163 | vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL] = vcpu->arch.gpr[rs]; | ||
164 | break; | ||
165 | case SPRN_IVOR9: | ||
166 | vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] = vcpu->arch.gpr[rs]; | ||
167 | break; | ||
168 | case SPRN_IVOR10: | ||
169 | vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER] = vcpu->arch.gpr[rs]; | ||
170 | break; | ||
171 | case SPRN_IVOR11: | ||
172 | vcpu->arch.ivor[BOOKE_IRQPRIO_FIT] = vcpu->arch.gpr[rs]; | ||
173 | break; | ||
174 | case SPRN_IVOR12: | ||
175 | vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG] = vcpu->arch.gpr[rs]; | ||
176 | break; | ||
177 | case SPRN_IVOR13: | ||
178 | vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS] = vcpu->arch.gpr[rs]; | ||
179 | break; | ||
180 | case SPRN_IVOR14: | ||
181 | vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS] = vcpu->arch.gpr[rs]; | ||
182 | break; | ||
183 | case SPRN_IVOR15: | ||
184 | vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = vcpu->arch.gpr[rs]; | ||
185 | break; | ||
186 | |||
187 | default: | ||
188 | emulated = EMULATE_FAIL; | ||
189 | } | ||
190 | |||
191 | return emulated; | ||
192 | } | ||
193 | |||
194 | int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||
195 | { | ||
196 | int emulated = EMULATE_DONE; | ||
197 | |||
198 | switch (sprn) { | ||
199 | case SPRN_IVPR: | ||
200 | vcpu->arch.gpr[rt] = vcpu->arch.ivpr; break; | ||
201 | case SPRN_DEAR: | ||
202 | vcpu->arch.gpr[rt] = vcpu->arch.dear; break; | ||
203 | case SPRN_ESR: | ||
204 | vcpu->arch.gpr[rt] = vcpu->arch.esr; break; | ||
205 | case SPRN_DBCR0: | ||
206 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr0; break; | ||
207 | case SPRN_DBCR1: | ||
208 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr1; break; | ||
209 | case SPRN_DBSR: | ||
210 | vcpu->arch.gpr[rt] = vcpu->arch.dbsr; break; | ||
211 | |||
212 | case SPRN_IVOR0: | ||
213 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]; | ||
214 | break; | ||
215 | case SPRN_IVOR1: | ||
216 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK]; | ||
217 | break; | ||
218 | case SPRN_IVOR2: | ||
219 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]; | ||
220 | break; | ||
221 | case SPRN_IVOR3: | ||
222 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE]; | ||
223 | break; | ||
224 | case SPRN_IVOR4: | ||
225 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL]; | ||
226 | break; | ||
227 | case SPRN_IVOR5: | ||
228 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT]; | ||
229 | break; | ||
230 | case SPRN_IVOR6: | ||
231 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM]; | ||
232 | break; | ||
233 | case SPRN_IVOR7: | ||
234 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL]; | ||
235 | break; | ||
236 | case SPRN_IVOR8: | ||
237 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL]; | ||
238 | break; | ||
239 | case SPRN_IVOR9: | ||
240 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL]; | ||
241 | break; | ||
242 | case SPRN_IVOR10: | ||
243 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER]; | ||
244 | break; | ||
245 | case SPRN_IVOR11: | ||
246 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_FIT]; | ||
247 | break; | ||
248 | case SPRN_IVOR12: | ||
249 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG]; | ||
250 | break; | ||
251 | case SPRN_IVOR13: | ||
252 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS]; | ||
253 | break; | ||
254 | case SPRN_IVOR14: | ||
255 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS]; | ||
256 | break; | ||
257 | case SPRN_IVOR15: | ||
258 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG]; | ||
259 | break; | ||
260 | |||
261 | default: | ||
262 | emulated = EMULATE_FAIL; | ||
263 | } | ||
264 | |||
265 | return emulated; | ||
266 | } | ||
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S index 084ebcd7dd83..d0c6f841bbd1 100644 --- a/arch/powerpc/kvm/booke_interrupts.S +++ b/arch/powerpc/kvm/booke_interrupts.S | |||
@@ -86,6 +86,9 @@ KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG | |||
86 | KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS | 86 | KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS |
87 | KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS | 87 | KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS |
88 | KVM_HANDLER BOOKE_INTERRUPT_DEBUG | 88 | KVM_HANDLER BOOKE_INTERRUPT_DEBUG |
89 | KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL | ||
90 | KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA | ||
91 | KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND | ||
89 | 92 | ||
90 | _GLOBAL(kvmppc_handler_len) | 93 | _GLOBAL(kvmppc_handler_len) |
91 | .long kvmppc_handler_1 - kvmppc_handler_0 | 94 | .long kvmppc_handler_1 - kvmppc_handler_0 |
@@ -347,7 +350,9 @@ lightweight_exit: | |||
347 | lwz r3, VCPU_SHADOW_PID(r4) | 350 | lwz r3, VCPU_SHADOW_PID(r4) |
348 | mtspr SPRN_PID, r3 | 351 | mtspr SPRN_PID, r3 |
349 | 352 | ||
353 | #ifdef CONFIG_44x | ||
350 | iccci 0, 0 /* XXX hack */ | 354 | iccci 0, 0 /* XXX hack */ |
355 | #endif | ||
351 | 356 | ||
352 | /* Load some guest volatiles. */ | 357 | /* Load some guest volatiles. */ |
353 | lwz r0, VCPU_GPR(r0)(r4) | 358 | lwz r0, VCPU_GPR(r0)(r4) |
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c new file mode 100644 index 000000000000..d8067fd81cdd --- /dev/null +++ b/arch/powerpc/kvm/e500.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: Yu Liu, <yu.liu@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * This file is derived from arch/powerpc/kvm/44x.c, | ||
8 | * by Hollis Blanchard <hollisb@us.ibm.com>. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License, version 2, as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kvm_host.h> | ||
16 | #include <linux/err.h> | ||
17 | |||
18 | #include <asm/reg.h> | ||
19 | #include <asm/cputable.h> | ||
20 | #include <asm/tlbflush.h> | ||
21 | #include <asm/kvm_e500.h> | ||
22 | #include <asm/kvm_ppc.h> | ||
23 | |||
24 | #include "booke.h" | ||
25 | #include "e500_tlb.h" | ||
26 | |||
27 | void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) | ||
28 | { | ||
29 | } | ||
30 | |||
31 | void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) | ||
32 | { | ||
33 | } | ||
34 | |||
35 | void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||
36 | { | ||
37 | kvmppc_e500_tlb_load(vcpu, cpu); | ||
38 | } | ||
39 | |||
40 | void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) | ||
41 | { | ||
42 | kvmppc_e500_tlb_put(vcpu); | ||
43 | } | ||
44 | |||
45 | int kvmppc_core_check_processor_compat(void) | ||
46 | { | ||
47 | int r; | ||
48 | |||
49 | if (strcmp(cur_cpu_spec->cpu_name, "e500v2") == 0) | ||
50 | r = 0; | ||
51 | else | ||
52 | r = -ENOTSUPP; | ||
53 | |||
54 | return r; | ||
55 | } | ||
56 | |||
57 | int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu) | ||
58 | { | ||
59 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
60 | |||
61 | kvmppc_e500_tlb_setup(vcpu_e500); | ||
62 | |||
63 | /* Use the same core vertion as host's */ | ||
64 | vcpu->arch.pvr = mfspr(SPRN_PVR); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | /* 'linear_address' is actually an encoding of AS|PID|EADDR . */ | ||
70 | int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, | ||
71 | struct kvm_translation *tr) | ||
72 | { | ||
73 | int index; | ||
74 | gva_t eaddr; | ||
75 | u8 pid; | ||
76 | u8 as; | ||
77 | |||
78 | eaddr = tr->linear_address; | ||
79 | pid = (tr->linear_address >> 32) & 0xff; | ||
80 | as = (tr->linear_address >> 40) & 0x1; | ||
81 | |||
82 | index = kvmppc_e500_tlb_search(vcpu, eaddr, pid, as); | ||
83 | if (index < 0) { | ||
84 | tr->valid = 0; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | tr->physical_address = kvmppc_mmu_xlate(vcpu, index, eaddr); | ||
89 | /* XXX what does "writeable" and "usermode" even mean? */ | ||
90 | tr->valid = 1; | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) | ||
96 | { | ||
97 | struct kvmppc_vcpu_e500 *vcpu_e500; | ||
98 | struct kvm_vcpu *vcpu; | ||
99 | int err; | ||
100 | |||
101 | vcpu_e500 = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); | ||
102 | if (!vcpu_e500) { | ||
103 | err = -ENOMEM; | ||
104 | goto out; | ||
105 | } | ||
106 | |||
107 | vcpu = &vcpu_e500->vcpu; | ||
108 | err = kvm_vcpu_init(vcpu, kvm, id); | ||
109 | if (err) | ||
110 | goto free_vcpu; | ||
111 | |||
112 | err = kvmppc_e500_tlb_init(vcpu_e500); | ||
113 | if (err) | ||
114 | goto uninit_vcpu; | ||
115 | |||
116 | return vcpu; | ||
117 | |||
118 | uninit_vcpu: | ||
119 | kvm_vcpu_uninit(vcpu); | ||
120 | free_vcpu: | ||
121 | kmem_cache_free(kvm_vcpu_cache, vcpu_e500); | ||
122 | out: | ||
123 | return ERR_PTR(err); | ||
124 | } | ||
125 | |||
126 | void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) | ||
127 | { | ||
128 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
129 | |||
130 | kvmppc_e500_tlb_uninit(vcpu_e500); | ||
131 | kvm_vcpu_uninit(vcpu); | ||
132 | kmem_cache_free(kvm_vcpu_cache, vcpu_e500); | ||
133 | } | ||
134 | |||
135 | static int kvmppc_e500_init(void) | ||
136 | { | ||
137 | int r, i; | ||
138 | unsigned long ivor[3]; | ||
139 | unsigned long max_ivor = 0; | ||
140 | |||
141 | r = kvmppc_booke_init(); | ||
142 | if (r) | ||
143 | return r; | ||
144 | |||
145 | /* copy extra E500 exception handlers */ | ||
146 | ivor[0] = mfspr(SPRN_IVOR32); | ||
147 | ivor[1] = mfspr(SPRN_IVOR33); | ||
148 | ivor[2] = mfspr(SPRN_IVOR34); | ||
149 | for (i = 0; i < 3; i++) { | ||
150 | if (ivor[i] > max_ivor) | ||
151 | max_ivor = ivor[i]; | ||
152 | |||
153 | memcpy((void *)kvmppc_booke_handlers + ivor[i], | ||
154 | kvmppc_handlers_start + (i + 16) * kvmppc_handler_len, | ||
155 | kvmppc_handler_len); | ||
156 | } | ||
157 | flush_icache_range(kvmppc_booke_handlers, | ||
158 | kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); | ||
159 | |||
160 | return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), THIS_MODULE); | ||
161 | } | ||
162 | |||
163 | static void kvmppc_e500_exit(void) | ||
164 | { | ||
165 | kvmppc_booke_exit(); | ||
166 | } | ||
167 | |||
168 | module_init(kvmppc_e500_init); | ||
169 | module_exit(kvmppc_e500_exit); | ||
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c new file mode 100644 index 000000000000..3f760414b9f8 --- /dev/null +++ b/arch/powerpc/kvm/e500_emulate.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: Yu Liu, <yu.liu@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * This file is derived from arch/powerpc/kvm/44x_emulate.c, | ||
8 | * by Hollis Blanchard <hollisb@us.ibm.com>. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License, version 2, as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <asm/kvm_ppc.h> | ||
16 | #include <asm/disassemble.h> | ||
17 | #include <asm/kvm_e500.h> | ||
18 | |||
19 | #include "booke.h" | ||
20 | #include "e500_tlb.h" | ||
21 | |||
22 | #define XOP_TLBIVAX 786 | ||
23 | #define XOP_TLBSX 914 | ||
24 | #define XOP_TLBRE 946 | ||
25 | #define XOP_TLBWE 978 | ||
26 | |||
27 | int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
28 | unsigned int inst, int *advance) | ||
29 | { | ||
30 | int emulated = EMULATE_DONE; | ||
31 | int ra; | ||
32 | int rb; | ||
33 | |||
34 | switch (get_op(inst)) { | ||
35 | case 31: | ||
36 | switch (get_xop(inst)) { | ||
37 | |||
38 | case XOP_TLBRE: | ||
39 | emulated = kvmppc_e500_emul_tlbre(vcpu); | ||
40 | break; | ||
41 | |||
42 | case XOP_TLBWE: | ||
43 | emulated = kvmppc_e500_emul_tlbwe(vcpu); | ||
44 | break; | ||
45 | |||
46 | case XOP_TLBSX: | ||
47 | rb = get_rb(inst); | ||
48 | emulated = kvmppc_e500_emul_tlbsx(vcpu,rb); | ||
49 | break; | ||
50 | |||
51 | case XOP_TLBIVAX: | ||
52 | ra = get_ra(inst); | ||
53 | rb = get_rb(inst); | ||
54 | emulated = kvmppc_e500_emul_tlbivax(vcpu, ra, rb); | ||
55 | break; | ||
56 | |||
57 | default: | ||
58 | emulated = EMULATE_FAIL; | ||
59 | } | ||
60 | |||
61 | break; | ||
62 | |||
63 | default: | ||
64 | emulated = EMULATE_FAIL; | ||
65 | } | ||
66 | |||
67 | if (emulated == EMULATE_FAIL) | ||
68 | emulated = kvmppc_booke_emulate_op(run, vcpu, inst, advance); | ||
69 | |||
70 | return emulated; | ||
71 | } | ||
72 | |||
73 | int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||
74 | { | ||
75 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
76 | int emulated = EMULATE_DONE; | ||
77 | |||
78 | switch (sprn) { | ||
79 | case SPRN_PID: | ||
80 | vcpu_e500->pid[0] = vcpu->arch.shadow_pid = | ||
81 | vcpu->arch.pid = vcpu->arch.gpr[rs]; | ||
82 | break; | ||
83 | case SPRN_PID1: | ||
84 | vcpu_e500->pid[1] = vcpu->arch.gpr[rs]; break; | ||
85 | case SPRN_PID2: | ||
86 | vcpu_e500->pid[2] = vcpu->arch.gpr[rs]; break; | ||
87 | case SPRN_MAS0: | ||
88 | vcpu_e500->mas0 = vcpu->arch.gpr[rs]; break; | ||
89 | case SPRN_MAS1: | ||
90 | vcpu_e500->mas1 = vcpu->arch.gpr[rs]; break; | ||
91 | case SPRN_MAS2: | ||
92 | vcpu_e500->mas2 = vcpu->arch.gpr[rs]; break; | ||
93 | case SPRN_MAS3: | ||
94 | vcpu_e500->mas3 = vcpu->arch.gpr[rs]; break; | ||
95 | case SPRN_MAS4: | ||
96 | vcpu_e500->mas4 = vcpu->arch.gpr[rs]; break; | ||
97 | case SPRN_MAS6: | ||
98 | vcpu_e500->mas6 = vcpu->arch.gpr[rs]; break; | ||
99 | case SPRN_MAS7: | ||
100 | vcpu_e500->mas7 = vcpu->arch.gpr[rs]; break; | ||
101 | case SPRN_L1CSR1: | ||
102 | vcpu_e500->l1csr1 = vcpu->arch.gpr[rs]; break; | ||
103 | case SPRN_HID0: | ||
104 | vcpu_e500->hid0 = vcpu->arch.gpr[rs]; break; | ||
105 | case SPRN_HID1: | ||
106 | vcpu_e500->hid1 = vcpu->arch.gpr[rs]; break; | ||
107 | |||
108 | case SPRN_MMUCSR0: | ||
109 | emulated = kvmppc_e500_emul_mt_mmucsr0(vcpu_e500, | ||
110 | vcpu->arch.gpr[rs]); | ||
111 | break; | ||
112 | |||
113 | /* extra exceptions */ | ||
114 | case SPRN_IVOR32: | ||
115 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = vcpu->arch.gpr[rs]; | ||
116 | break; | ||
117 | case SPRN_IVOR33: | ||
118 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] = vcpu->arch.gpr[rs]; | ||
119 | break; | ||
120 | case SPRN_IVOR34: | ||
121 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = vcpu->arch.gpr[rs]; | ||
122 | break; | ||
123 | case SPRN_IVOR35: | ||
124 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = vcpu->arch.gpr[rs]; | ||
125 | break; | ||
126 | |||
127 | default: | ||
128 | emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, rs); | ||
129 | } | ||
130 | |||
131 | return emulated; | ||
132 | } | ||
133 | |||
134 | int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||
135 | { | ||
136 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
137 | int emulated = EMULATE_DONE; | ||
138 | |||
139 | switch (sprn) { | ||
140 | case SPRN_PID: | ||
141 | vcpu->arch.gpr[rt] = vcpu_e500->pid[0]; break; | ||
142 | case SPRN_PID1: | ||
143 | vcpu->arch.gpr[rt] = vcpu_e500->pid[1]; break; | ||
144 | case SPRN_PID2: | ||
145 | vcpu->arch.gpr[rt] = vcpu_e500->pid[2]; break; | ||
146 | case SPRN_MAS0: | ||
147 | vcpu->arch.gpr[rt] = vcpu_e500->mas0; break; | ||
148 | case SPRN_MAS1: | ||
149 | vcpu->arch.gpr[rt] = vcpu_e500->mas1; break; | ||
150 | case SPRN_MAS2: | ||
151 | vcpu->arch.gpr[rt] = vcpu_e500->mas2; break; | ||
152 | case SPRN_MAS3: | ||
153 | vcpu->arch.gpr[rt] = vcpu_e500->mas3; break; | ||
154 | case SPRN_MAS4: | ||
155 | vcpu->arch.gpr[rt] = vcpu_e500->mas4; break; | ||
156 | case SPRN_MAS6: | ||
157 | vcpu->arch.gpr[rt] = vcpu_e500->mas6; break; | ||
158 | case SPRN_MAS7: | ||
159 | vcpu->arch.gpr[rt] = vcpu_e500->mas7; break; | ||
160 | |||
161 | case SPRN_TLB0CFG: | ||
162 | vcpu->arch.gpr[rt] = mfspr(SPRN_TLB0CFG); | ||
163 | vcpu->arch.gpr[rt] &= ~0xfffUL; | ||
164 | vcpu->arch.gpr[rt] |= vcpu_e500->guest_tlb_size[0]; | ||
165 | break; | ||
166 | |||
167 | case SPRN_TLB1CFG: | ||
168 | vcpu->arch.gpr[rt] = mfspr(SPRN_TLB1CFG); | ||
169 | vcpu->arch.gpr[rt] &= ~0xfffUL; | ||
170 | vcpu->arch.gpr[rt] |= vcpu_e500->guest_tlb_size[1]; | ||
171 | break; | ||
172 | |||
173 | case SPRN_L1CSR1: | ||
174 | vcpu->arch.gpr[rt] = vcpu_e500->l1csr1; break; | ||
175 | case SPRN_HID0: | ||
176 | vcpu->arch.gpr[rt] = vcpu_e500->hid0; break; | ||
177 | case SPRN_HID1: | ||
178 | vcpu->arch.gpr[rt] = vcpu_e500->hid1; break; | ||
179 | |||
180 | case SPRN_MMUCSR0: | ||
181 | vcpu->arch.gpr[rt] = 0; break; | ||
182 | |||
183 | /* extra exceptions */ | ||
184 | case SPRN_IVOR32: | ||
185 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; | ||
186 | break; | ||
187 | case SPRN_IVOR33: | ||
188 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA]; | ||
189 | break; | ||
190 | case SPRN_IVOR34: | ||
191 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; | ||
192 | break; | ||
193 | case SPRN_IVOR35: | ||
194 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; | ||
195 | break; | ||
196 | default: | ||
197 | emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, rt); | ||
198 | } | ||
199 | |||
200 | return emulated; | ||
201 | } | ||
202 | |||
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c new file mode 100644 index 000000000000..0e773fc2d5e4 --- /dev/null +++ b/arch/powerpc/kvm/e500_tlb.c | |||
@@ -0,0 +1,757 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: Yu Liu, yu.liu@freescale.com | ||
5 | * | ||
6 | * Description: | ||
7 | * This file is based on arch/powerpc/kvm/44x_tlb.c, | ||
8 | * by Hollis Blanchard <hollisb@us.ibm.com>. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License, version 2, as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/kvm.h> | ||
18 | #include <linux/kvm_host.h> | ||
19 | #include <linux/highmem.h> | ||
20 | #include <asm/kvm_ppc.h> | ||
21 | #include <asm/kvm_e500.h> | ||
22 | |||
23 | #include "../mm/mmu_decl.h" | ||
24 | #include "e500_tlb.h" | ||
25 | |||
26 | #define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1) | ||
27 | |||
28 | static unsigned int tlb1_entry_num; | ||
29 | |||
30 | void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) | ||
31 | { | ||
32 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
33 | struct tlbe *tlbe; | ||
34 | int i, tlbsel; | ||
35 | |||
36 | printk("| %8s | %8s | %8s | %8s | %8s |\n", | ||
37 | "nr", "mas1", "mas2", "mas3", "mas7"); | ||
38 | |||
39 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { | ||
40 | printk("Guest TLB%d:\n", tlbsel); | ||
41 | for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) { | ||
42 | tlbe = &vcpu_e500->guest_tlb[tlbsel][i]; | ||
43 | if (tlbe->mas1 & MAS1_VALID) | ||
44 | printk(" G[%d][%3d] | %08X | %08X | %08X | %08X |\n", | ||
45 | tlbsel, i, tlbe->mas1, tlbe->mas2, | ||
46 | tlbe->mas3, tlbe->mas7); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { | ||
51 | printk("Shadow TLB%d:\n", tlbsel); | ||
52 | for (i = 0; i < vcpu_e500->shadow_tlb_size[tlbsel]; i++) { | ||
53 | tlbe = &vcpu_e500->shadow_tlb[tlbsel][i]; | ||
54 | if (tlbe->mas1 & MAS1_VALID) | ||
55 | printk(" S[%d][%3d] | %08X | %08X | %08X | %08X |\n", | ||
56 | tlbsel, i, tlbe->mas1, tlbe->mas2, | ||
57 | tlbe->mas3, tlbe->mas7); | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static inline unsigned int tlb0_get_next_victim( | ||
63 | struct kvmppc_vcpu_e500 *vcpu_e500) | ||
64 | { | ||
65 | unsigned int victim; | ||
66 | |||
67 | victim = vcpu_e500->guest_tlb_nv[0]++; | ||
68 | if (unlikely(vcpu_e500->guest_tlb_nv[0] >= KVM_E500_TLB0_WAY_NUM)) | ||
69 | vcpu_e500->guest_tlb_nv[0] = 0; | ||
70 | |||
71 | return victim; | ||
72 | } | ||
73 | |||
74 | static inline unsigned int tlb1_max_shadow_size(void) | ||
75 | { | ||
76 | return tlb1_entry_num - tlbcam_index; | ||
77 | } | ||
78 | |||
79 | static inline int tlbe_is_writable(struct tlbe *tlbe) | ||
80 | { | ||
81 | return tlbe->mas3 & (MAS3_SW|MAS3_UW); | ||
82 | } | ||
83 | |||
84 | static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode) | ||
85 | { | ||
86 | /* Mask off reserved bits. */ | ||
87 | mas3 &= MAS3_ATTRIB_MASK; | ||
88 | |||
89 | if (!usermode) { | ||
90 | /* Guest is in supervisor mode, | ||
91 | * so we need to translate guest | ||
92 | * supervisor permissions into user permissions. */ | ||
93 | mas3 &= ~E500_TLB_USER_PERM_MASK; | ||
94 | mas3 |= (mas3 & E500_TLB_SUPER_PERM_MASK) << 1; | ||
95 | } | ||
96 | |||
97 | return mas3 | E500_TLB_SUPER_PERM_MASK; | ||
98 | } | ||
99 | |||
100 | static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode) | ||
101 | { | ||
102 | #ifdef CONFIG_SMP | ||
103 | return (mas2 & MAS2_ATTRIB_MASK) | MAS2_M; | ||
104 | #else | ||
105 | return mas2 & MAS2_ATTRIB_MASK; | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * writing shadow tlb entry to host TLB | ||
111 | */ | ||
112 | static inline void __write_host_tlbe(struct tlbe *stlbe) | ||
113 | { | ||
114 | mtspr(SPRN_MAS1, stlbe->mas1); | ||
115 | mtspr(SPRN_MAS2, stlbe->mas2); | ||
116 | mtspr(SPRN_MAS3, stlbe->mas3); | ||
117 | mtspr(SPRN_MAS7, stlbe->mas7); | ||
118 | __asm__ __volatile__ ("tlbwe\n" : : ); | ||
119 | } | ||
120 | |||
121 | static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
122 | int tlbsel, int esel) | ||
123 | { | ||
124 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | ||
125 | |||
126 | local_irq_disable(); | ||
127 | if (tlbsel == 0) { | ||
128 | __write_host_tlbe(stlbe); | ||
129 | } else { | ||
130 | unsigned register mas0; | ||
131 | |||
132 | mas0 = mfspr(SPRN_MAS0); | ||
133 | |||
134 | mtspr(SPRN_MAS0, MAS0_TLBSEL(1) | MAS0_ESEL(to_htlb1_esel(esel))); | ||
135 | __write_host_tlbe(stlbe); | ||
136 | |||
137 | mtspr(SPRN_MAS0, mas0); | ||
138 | } | ||
139 | local_irq_enable(); | ||
140 | } | ||
141 | |||
142 | void kvmppc_e500_tlb_load(struct kvm_vcpu *vcpu, int cpu) | ||
143 | { | ||
144 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
145 | int i; | ||
146 | unsigned register mas0; | ||
147 | |||
148 | /* Load all valid TLB1 entries to reduce guest tlb miss fault */ | ||
149 | local_irq_disable(); | ||
150 | mas0 = mfspr(SPRN_MAS0); | ||
151 | for (i = 0; i < tlb1_max_shadow_size(); i++) { | ||
152 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[1][i]; | ||
153 | |||
154 | if (get_tlb_v(stlbe)) { | ||
155 | mtspr(SPRN_MAS0, MAS0_TLBSEL(1) | ||
156 | | MAS0_ESEL(to_htlb1_esel(i))); | ||
157 | __write_host_tlbe(stlbe); | ||
158 | } | ||
159 | } | ||
160 | mtspr(SPRN_MAS0, mas0); | ||
161 | local_irq_enable(); | ||
162 | } | ||
163 | |||
164 | void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu) | ||
165 | { | ||
166 | _tlbil_all(); | ||
167 | } | ||
168 | |||
169 | /* Search the guest TLB for a matching entry. */ | ||
170 | static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
171 | gva_t eaddr, int tlbsel, unsigned int pid, int as) | ||
172 | { | ||
173 | int i; | ||
174 | |||
175 | /* XXX Replace loop with fancy data structures. */ | ||
176 | for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) { | ||
177 | struct tlbe *tlbe = &vcpu_e500->guest_tlb[tlbsel][i]; | ||
178 | unsigned int tid; | ||
179 | |||
180 | if (eaddr < get_tlb_eaddr(tlbe)) | ||
181 | continue; | ||
182 | |||
183 | if (eaddr > get_tlb_end(tlbe)) | ||
184 | continue; | ||
185 | |||
186 | tid = get_tlb_tid(tlbe); | ||
187 | if (tid && (tid != pid)) | ||
188 | continue; | ||
189 | |||
190 | if (!get_tlb_v(tlbe)) | ||
191 | continue; | ||
192 | |||
193 | if (get_tlb_ts(tlbe) != as && as != -1) | ||
194 | continue; | ||
195 | |||
196 | return i; | ||
197 | } | ||
198 | |||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | static void kvmppc_e500_shadow_release(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
203 | int tlbsel, int esel) | ||
204 | { | ||
205 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | ||
206 | struct page *page = vcpu_e500->shadow_pages[tlbsel][esel]; | ||
207 | |||
208 | if (page) { | ||
209 | vcpu_e500->shadow_pages[tlbsel][esel] = NULL; | ||
210 | |||
211 | if (get_tlb_v(stlbe)) { | ||
212 | if (tlbe_is_writable(stlbe)) | ||
213 | kvm_release_page_dirty(page); | ||
214 | else | ||
215 | kvm_release_page_clean(page); | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
221 | int tlbsel, int esel) | ||
222 | { | ||
223 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | ||
224 | |||
225 | kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel); | ||
226 | stlbe->mas1 = 0; | ||
227 | KVMTRACE_5D(STLB_INVAL, &vcpu_e500->vcpu, index_of(tlbsel, esel), | ||
228 | stlbe->mas1, stlbe->mas2, stlbe->mas3, stlbe->mas7, | ||
229 | handler); | ||
230 | } | ||
231 | |||
232 | static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
233 | gva_t eaddr, gva_t eend, u32 tid) | ||
234 | { | ||
235 | unsigned int pid = tid & 0xff; | ||
236 | unsigned int i; | ||
237 | |||
238 | /* XXX Replace loop with fancy data structures. */ | ||
239 | for (i = 0; i < vcpu_e500->guest_tlb_size[1]; i++) { | ||
240 | struct tlbe *stlbe = &vcpu_e500->shadow_tlb[1][i]; | ||
241 | unsigned int tid; | ||
242 | |||
243 | if (!get_tlb_v(stlbe)) | ||
244 | continue; | ||
245 | |||
246 | if (eend < get_tlb_eaddr(stlbe)) | ||
247 | continue; | ||
248 | |||
249 | if (eaddr > get_tlb_end(stlbe)) | ||
250 | continue; | ||
251 | |||
252 | tid = get_tlb_tid(stlbe); | ||
253 | if (tid && (tid != pid)) | ||
254 | continue; | ||
255 | |||
256 | kvmppc_e500_stlbe_invalidate(vcpu_e500, 1, i); | ||
257 | write_host_tlbe(vcpu_e500, 1, i); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | ||
262 | unsigned int eaddr, int as) | ||
263 | { | ||
264 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
265 | unsigned int victim, pidsel, tsized; | ||
266 | int tlbsel; | ||
267 | |||
268 | /* since we only have two TLBs, only lower bit is used. */ | ||
269 | tlbsel = (vcpu_e500->mas4 >> 28) & 0x1; | ||
270 | victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0; | ||
271 | pidsel = (vcpu_e500->mas4 >> 16) & 0xf; | ||
272 | tsized = (vcpu_e500->mas4 >> 8) & 0xf; | ||
273 | |||
274 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) | ||
275 | | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | ||
276 | vcpu_e500->mas1 = MAS1_VALID | (as ? MAS1_TS : 0) | ||
277 | | MAS1_TID(vcpu_e500->pid[pidsel]) | ||
278 | | MAS1_TSIZE(tsized); | ||
279 | vcpu_e500->mas2 = (eaddr & MAS2_EPN) | ||
280 | | (vcpu_e500->mas4 & MAS2_ATTRIB_MASK); | ||
281 | vcpu_e500->mas3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3; | ||
282 | vcpu_e500->mas6 = (vcpu_e500->mas6 & MAS6_SPID1) | ||
283 | | (get_cur_pid(vcpu) << 16) | ||
284 | | (as ? MAS6_SAS : 0); | ||
285 | vcpu_e500->mas7 = 0; | ||
286 | } | ||
287 | |||
288 | static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
289 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel) | ||
290 | { | ||
291 | struct page *new_page; | ||
292 | struct tlbe *stlbe; | ||
293 | hpa_t hpaddr; | ||
294 | |||
295 | stlbe = &vcpu_e500->shadow_tlb[tlbsel][esel]; | ||
296 | |||
297 | /* Get reference to new page. */ | ||
298 | new_page = gfn_to_page(vcpu_e500->vcpu.kvm, gfn); | ||
299 | if (is_error_page(new_page)) { | ||
300 | printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn); | ||
301 | kvm_release_page_clean(new_page); | ||
302 | return; | ||
303 | } | ||
304 | hpaddr = page_to_phys(new_page); | ||
305 | |||
306 | /* Drop reference to old page. */ | ||
307 | kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel); | ||
308 | |||
309 | vcpu_e500->shadow_pages[tlbsel][esel] = new_page; | ||
310 | |||
311 | /* Force TS=1 IPROT=0 TSIZE=4KB for all guest mappings. */ | ||
312 | stlbe->mas1 = MAS1_TSIZE(BOOKE_PAGESZ_4K) | ||
313 | | MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID; | ||
314 | stlbe->mas2 = (gvaddr & MAS2_EPN) | ||
315 | | e500_shadow_mas2_attrib(gtlbe->mas2, | ||
316 | vcpu_e500->vcpu.arch.msr & MSR_PR); | ||
317 | stlbe->mas3 = (hpaddr & MAS3_RPN) | ||
318 | | e500_shadow_mas3_attrib(gtlbe->mas3, | ||
319 | vcpu_e500->vcpu.arch.msr & MSR_PR); | ||
320 | stlbe->mas7 = (hpaddr >> 32) & MAS7_RPN; | ||
321 | |||
322 | KVMTRACE_5D(STLB_WRITE, &vcpu_e500->vcpu, index_of(tlbsel, esel), | ||
323 | stlbe->mas1, stlbe->mas2, stlbe->mas3, stlbe->mas7, | ||
324 | handler); | ||
325 | } | ||
326 | |||
327 | /* XXX only map the one-one case, for now use TLB0 */ | ||
328 | static int kvmppc_e500_stlbe_map(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
329 | int tlbsel, int esel) | ||
330 | { | ||
331 | struct tlbe *gtlbe; | ||
332 | |||
333 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | ||
334 | |||
335 | kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), | ||
336 | get_tlb_raddr(gtlbe) >> PAGE_SHIFT, | ||
337 | gtlbe, tlbsel, esel); | ||
338 | |||
339 | return esel; | ||
340 | } | ||
341 | |||
342 | /* Caller must ensure that the specified guest TLB entry is safe to insert into | ||
343 | * the shadow TLB. */ | ||
344 | /* XXX for both one-one and one-to-many , for now use TLB1 */ | ||
345 | static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
346 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe) | ||
347 | { | ||
348 | unsigned int victim; | ||
349 | |||
350 | victim = vcpu_e500->guest_tlb_nv[1]++; | ||
351 | |||
352 | if (unlikely(vcpu_e500->guest_tlb_nv[1] >= tlb1_max_shadow_size())) | ||
353 | vcpu_e500->guest_tlb_nv[1] = 0; | ||
354 | |||
355 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim); | ||
356 | |||
357 | return victim; | ||
358 | } | ||
359 | |||
360 | /* Invalidate all guest kernel mappings when enter usermode, | ||
361 | * so that when they fault back in they will get the | ||
362 | * proper permission bits. */ | ||
363 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) | ||
364 | { | ||
365 | if (usermode) { | ||
366 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
367 | int i; | ||
368 | |||
369 | /* XXX Replace loop with fancy data structures. */ | ||
370 | for (i = 0; i < tlb1_max_shadow_size(); i++) | ||
371 | kvmppc_e500_stlbe_invalidate(vcpu_e500, 1, i); | ||
372 | |||
373 | _tlbil_all(); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | static int kvmppc_e500_gtlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
378 | int tlbsel, int esel) | ||
379 | { | ||
380 | struct tlbe *gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | ||
381 | |||
382 | if (unlikely(get_tlb_iprot(gtlbe))) | ||
383 | return -1; | ||
384 | |||
385 | if (tlbsel == 1) { | ||
386 | kvmppc_e500_tlb1_invalidate(vcpu_e500, get_tlb_eaddr(gtlbe), | ||
387 | get_tlb_end(gtlbe), | ||
388 | get_tlb_tid(gtlbe)); | ||
389 | } else { | ||
390 | kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel); | ||
391 | } | ||
392 | |||
393 | gtlbe->mas1 = 0; | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value) | ||
399 | { | ||
400 | int esel; | ||
401 | |||
402 | if (value & MMUCSR0_TLB0FI) | ||
403 | for (esel = 0; esel < vcpu_e500->guest_tlb_size[0]; esel++) | ||
404 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 0, esel); | ||
405 | if (value & MMUCSR0_TLB1FI) | ||
406 | for (esel = 0; esel < vcpu_e500->guest_tlb_size[1]; esel++) | ||
407 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel); | ||
408 | |||
409 | _tlbil_all(); | ||
410 | |||
411 | return EMULATE_DONE; | ||
412 | } | ||
413 | |||
414 | int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb) | ||
415 | { | ||
416 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
417 | unsigned int ia; | ||
418 | int esel, tlbsel; | ||
419 | gva_t ea; | ||
420 | |||
421 | ea = ((ra) ? vcpu->arch.gpr[ra] : 0) + vcpu->arch.gpr[rb]; | ||
422 | |||
423 | ia = (ea >> 2) & 0x1; | ||
424 | |||
425 | /* since we only have two TLBs, only lower bit is used. */ | ||
426 | tlbsel = (ea >> 3) & 0x1; | ||
427 | |||
428 | if (ia) { | ||
429 | /* invalidate all entries */ | ||
430 | for (esel = 0; esel < vcpu_e500->guest_tlb_size[tlbsel]; esel++) | ||
431 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); | ||
432 | } else { | ||
433 | ea &= 0xfffff000; | ||
434 | esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, | ||
435 | get_cur_pid(vcpu), -1); | ||
436 | if (esel >= 0) | ||
437 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); | ||
438 | } | ||
439 | |||
440 | _tlbil_all(); | ||
441 | |||
442 | return EMULATE_DONE; | ||
443 | } | ||
444 | |||
445 | int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu) | ||
446 | { | ||
447 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
448 | int tlbsel, esel; | ||
449 | struct tlbe *gtlbe; | ||
450 | |||
451 | tlbsel = get_tlb_tlbsel(vcpu_e500); | ||
452 | esel = get_tlb_esel(vcpu_e500, tlbsel); | ||
453 | |||
454 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | ||
455 | vcpu_e500->mas0 &= ~MAS0_NV(~0); | ||
456 | vcpu_e500->mas0 |= MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | ||
457 | vcpu_e500->mas1 = gtlbe->mas1; | ||
458 | vcpu_e500->mas2 = gtlbe->mas2; | ||
459 | vcpu_e500->mas3 = gtlbe->mas3; | ||
460 | vcpu_e500->mas7 = gtlbe->mas7; | ||
461 | |||
462 | return EMULATE_DONE; | ||
463 | } | ||
464 | |||
465 | int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) | ||
466 | { | ||
467 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
468 | int as = !!get_cur_sas(vcpu_e500); | ||
469 | unsigned int pid = get_cur_spid(vcpu_e500); | ||
470 | int esel, tlbsel; | ||
471 | struct tlbe *gtlbe = NULL; | ||
472 | gva_t ea; | ||
473 | |||
474 | ea = vcpu->arch.gpr[rb]; | ||
475 | |||
476 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { | ||
477 | esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as); | ||
478 | if (esel >= 0) { | ||
479 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | ||
480 | break; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | if (gtlbe) { | ||
485 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel) | ||
486 | | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | ||
487 | vcpu_e500->mas1 = gtlbe->mas1; | ||
488 | vcpu_e500->mas2 = gtlbe->mas2; | ||
489 | vcpu_e500->mas3 = gtlbe->mas3; | ||
490 | vcpu_e500->mas7 = gtlbe->mas7; | ||
491 | } else { | ||
492 | int victim; | ||
493 | |||
494 | /* since we only have two TLBs, only lower bit is used. */ | ||
495 | tlbsel = vcpu_e500->mas4 >> 28 & 0x1; | ||
496 | victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0; | ||
497 | |||
498 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) | ||
499 | | MAS0_NV(vcpu_e500->guest_tlb_nv[tlbsel]); | ||
500 | vcpu_e500->mas1 = (vcpu_e500->mas6 & MAS6_SPID0) | ||
501 | | (vcpu_e500->mas6 & (MAS6_SAS ? MAS1_TS : 0)) | ||
502 | | (vcpu_e500->mas4 & MAS4_TSIZED(~0)); | ||
503 | vcpu_e500->mas2 &= MAS2_EPN; | ||
504 | vcpu_e500->mas2 |= vcpu_e500->mas4 & MAS2_ATTRIB_MASK; | ||
505 | vcpu_e500->mas3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3; | ||
506 | vcpu_e500->mas7 = 0; | ||
507 | } | ||
508 | |||
509 | return EMULATE_DONE; | ||
510 | } | ||
511 | |||
512 | int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | ||
513 | { | ||
514 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
515 | u64 eaddr; | ||
516 | u64 raddr; | ||
517 | u32 tid; | ||
518 | struct tlbe *gtlbe; | ||
519 | int tlbsel, esel, stlbsel, sesel; | ||
520 | |||
521 | tlbsel = get_tlb_tlbsel(vcpu_e500); | ||
522 | esel = get_tlb_esel(vcpu_e500, tlbsel); | ||
523 | |||
524 | gtlbe = &vcpu_e500->guest_tlb[tlbsel][esel]; | ||
525 | |||
526 | if (get_tlb_v(gtlbe) && tlbsel == 1) { | ||
527 | eaddr = get_tlb_eaddr(gtlbe); | ||
528 | tid = get_tlb_tid(gtlbe); | ||
529 | kvmppc_e500_tlb1_invalidate(vcpu_e500, eaddr, | ||
530 | get_tlb_end(gtlbe), tid); | ||
531 | } | ||
532 | |||
533 | gtlbe->mas1 = vcpu_e500->mas1; | ||
534 | gtlbe->mas2 = vcpu_e500->mas2; | ||
535 | gtlbe->mas3 = vcpu_e500->mas3; | ||
536 | gtlbe->mas7 = vcpu_e500->mas7; | ||
537 | |||
538 | KVMTRACE_5D(GTLB_WRITE, vcpu, vcpu_e500->mas0, | ||
539 | gtlbe->mas1, gtlbe->mas2, gtlbe->mas3, gtlbe->mas7, | ||
540 | handler); | ||
541 | |||
542 | /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ | ||
543 | if (tlbe_is_host_safe(vcpu, gtlbe)) { | ||
544 | switch (tlbsel) { | ||
545 | case 0: | ||
546 | /* TLB0 */ | ||
547 | gtlbe->mas1 &= ~MAS1_TSIZE(~0); | ||
548 | gtlbe->mas1 |= MAS1_TSIZE(BOOKE_PAGESZ_4K); | ||
549 | |||
550 | stlbsel = 0; | ||
551 | sesel = kvmppc_e500_stlbe_map(vcpu_e500, 0, esel); | ||
552 | |||
553 | break; | ||
554 | |||
555 | case 1: | ||
556 | /* TLB1 */ | ||
557 | eaddr = get_tlb_eaddr(gtlbe); | ||
558 | raddr = get_tlb_raddr(gtlbe); | ||
559 | |||
560 | /* Create a 4KB mapping on the host. | ||
561 | * If the guest wanted a large page, | ||
562 | * only the first 4KB is mapped here and the rest | ||
563 | * are mapped on the fly. */ | ||
564 | stlbsel = 1; | ||
565 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, | ||
566 | raddr >> PAGE_SHIFT, gtlbe); | ||
567 | break; | ||
568 | |||
569 | default: | ||
570 | BUG(); | ||
571 | } | ||
572 | write_host_tlbe(vcpu_e500, stlbsel, sesel); | ||
573 | } | ||
574 | |||
575 | return EMULATE_DONE; | ||
576 | } | ||
577 | |||
578 | int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) | ||
579 | { | ||
580 | unsigned int as = !!(vcpu->arch.msr & MSR_IS); | ||
581 | |||
582 | return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as); | ||
583 | } | ||
584 | |||
585 | int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr) | ||
586 | { | ||
587 | unsigned int as = !!(vcpu->arch.msr & MSR_DS); | ||
588 | |||
589 | return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as); | ||
590 | } | ||
591 | |||
592 | void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu) | ||
593 | { | ||
594 | unsigned int as = !!(vcpu->arch.msr & MSR_IS); | ||
595 | |||
596 | kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.pc, as); | ||
597 | } | ||
598 | |||
599 | void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu) | ||
600 | { | ||
601 | unsigned int as = !!(vcpu->arch.msr & MSR_DS); | ||
602 | |||
603 | kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.fault_dear, as); | ||
604 | } | ||
605 | |||
606 | gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index, | ||
607 | gva_t eaddr) | ||
608 | { | ||
609 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
610 | struct tlbe *gtlbe = | ||
611 | &vcpu_e500->guest_tlb[tlbsel_of(index)][esel_of(index)]; | ||
612 | u64 pgmask = get_tlb_bytes(gtlbe) - 1; | ||
613 | |||
614 | return get_tlb_raddr(gtlbe) | (eaddr & pgmask); | ||
615 | } | ||
616 | |||
617 | void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) | ||
618 | { | ||
619 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
620 | int tlbsel, i; | ||
621 | |||
622 | for (tlbsel = 0; tlbsel < 2; tlbsel++) | ||
623 | for (i = 0; i < vcpu_e500->guest_tlb_size[tlbsel]; i++) | ||
624 | kvmppc_e500_shadow_release(vcpu_e500, tlbsel, i); | ||
625 | |||
626 | /* discard all guest mapping */ | ||
627 | _tlbil_all(); | ||
628 | } | ||
629 | |||
630 | void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | ||
631 | unsigned int index) | ||
632 | { | ||
633 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
634 | int tlbsel = tlbsel_of(index); | ||
635 | int esel = esel_of(index); | ||
636 | int stlbsel, sesel; | ||
637 | |||
638 | switch (tlbsel) { | ||
639 | case 0: | ||
640 | stlbsel = 0; | ||
641 | sesel = esel; | ||
642 | break; | ||
643 | |||
644 | case 1: { | ||
645 | gfn_t gfn = gpaddr >> PAGE_SHIFT; | ||
646 | struct tlbe *gtlbe | ||
647 | = &vcpu_e500->guest_tlb[tlbsel][esel]; | ||
648 | |||
649 | stlbsel = 1; | ||
650 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, gtlbe); | ||
651 | break; | ||
652 | } | ||
653 | |||
654 | default: | ||
655 | BUG(); | ||
656 | break; | ||
657 | } | ||
658 | write_host_tlbe(vcpu_e500, stlbsel, sesel); | ||
659 | } | ||
660 | |||
661 | int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu, | ||
662 | gva_t eaddr, unsigned int pid, int as) | ||
663 | { | ||
664 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
665 | int esel, tlbsel; | ||
666 | |||
667 | for (tlbsel = 0; tlbsel < 2; tlbsel++) { | ||
668 | esel = kvmppc_e500_tlb_index(vcpu_e500, eaddr, tlbsel, pid, as); | ||
669 | if (esel >= 0) | ||
670 | return index_of(tlbsel, esel); | ||
671 | } | ||
672 | |||
673 | return -1; | ||
674 | } | ||
675 | |||
676 | void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
677 | { | ||
678 | struct tlbe *tlbe; | ||
679 | |||
680 | /* Insert large initial mapping for guest. */ | ||
681 | tlbe = &vcpu_e500->guest_tlb[1][0]; | ||
682 | tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOKE_PAGESZ_256M); | ||
683 | tlbe->mas2 = 0; | ||
684 | tlbe->mas3 = E500_TLB_SUPER_PERM_MASK; | ||
685 | tlbe->mas7 = 0; | ||
686 | |||
687 | /* 4K map for serial output. Used by kernel wrapper. */ | ||
688 | tlbe = &vcpu_e500->guest_tlb[1][1]; | ||
689 | tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOKE_PAGESZ_4K); | ||
690 | tlbe->mas2 = (0xe0004500 & 0xFFFFF000) | MAS2_I | MAS2_G; | ||
691 | tlbe->mas3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK; | ||
692 | tlbe->mas7 = 0; | ||
693 | } | ||
694 | |||
695 | int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
696 | { | ||
697 | tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF; | ||
698 | |||
699 | vcpu_e500->guest_tlb_size[0] = KVM_E500_TLB0_SIZE; | ||
700 | vcpu_e500->guest_tlb[0] = | ||
701 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); | ||
702 | if (vcpu_e500->guest_tlb[0] == NULL) | ||
703 | goto err_out; | ||
704 | |||
705 | vcpu_e500->shadow_tlb_size[0] = KVM_E500_TLB0_SIZE; | ||
706 | vcpu_e500->shadow_tlb[0] = | ||
707 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); | ||
708 | if (vcpu_e500->shadow_tlb[0] == NULL) | ||
709 | goto err_out_guest0; | ||
710 | |||
711 | vcpu_e500->guest_tlb_size[1] = KVM_E500_TLB1_SIZE; | ||
712 | vcpu_e500->guest_tlb[1] = | ||
713 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL); | ||
714 | if (vcpu_e500->guest_tlb[1] == NULL) | ||
715 | goto err_out_shadow0; | ||
716 | |||
717 | vcpu_e500->shadow_tlb_size[1] = tlb1_entry_num; | ||
718 | vcpu_e500->shadow_tlb[1] = | ||
719 | kzalloc(sizeof(struct tlbe) * tlb1_entry_num, GFP_KERNEL); | ||
720 | if (vcpu_e500->shadow_tlb[1] == NULL) | ||
721 | goto err_out_guest1; | ||
722 | |||
723 | vcpu_e500->shadow_pages[0] = (struct page **) | ||
724 | kzalloc(sizeof(struct page *) * KVM_E500_TLB0_SIZE, GFP_KERNEL); | ||
725 | if (vcpu_e500->shadow_pages[0] == NULL) | ||
726 | goto err_out_shadow1; | ||
727 | |||
728 | vcpu_e500->shadow_pages[1] = (struct page **) | ||
729 | kzalloc(sizeof(struct page *) * tlb1_entry_num, GFP_KERNEL); | ||
730 | if (vcpu_e500->shadow_pages[1] == NULL) | ||
731 | goto err_out_page0; | ||
732 | |||
733 | return 0; | ||
734 | |||
735 | err_out_page0: | ||
736 | kfree(vcpu_e500->shadow_pages[0]); | ||
737 | err_out_shadow1: | ||
738 | kfree(vcpu_e500->shadow_tlb[1]); | ||
739 | err_out_guest1: | ||
740 | kfree(vcpu_e500->guest_tlb[1]); | ||
741 | err_out_shadow0: | ||
742 | kfree(vcpu_e500->shadow_tlb[0]); | ||
743 | err_out_guest0: | ||
744 | kfree(vcpu_e500->guest_tlb[0]); | ||
745 | err_out: | ||
746 | return -1; | ||
747 | } | ||
748 | |||
749 | void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
750 | { | ||
751 | kfree(vcpu_e500->shadow_pages[1]); | ||
752 | kfree(vcpu_e500->shadow_pages[0]); | ||
753 | kfree(vcpu_e500->shadow_tlb[1]); | ||
754 | kfree(vcpu_e500->guest_tlb[1]); | ||
755 | kfree(vcpu_e500->shadow_tlb[0]); | ||
756 | kfree(vcpu_e500->guest_tlb[0]); | ||
757 | } | ||
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h new file mode 100644 index 000000000000..45b064b76906 --- /dev/null +++ b/arch/powerpc/kvm/e500_tlb.h | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: Yu Liu, yu.liu@freescale.com | ||
5 | * | ||
6 | * Description: | ||
7 | * This file is based on arch/powerpc/kvm/44x_tlb.h, | ||
8 | * by Hollis Blanchard <hollisb@us.ibm.com>. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License, version 2, as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __KVM_E500_TLB_H__ | ||
16 | #define __KVM_E500_TLB_H__ | ||
17 | |||
18 | #include <linux/kvm_host.h> | ||
19 | #include <asm/mmu-fsl-booke.h> | ||
20 | #include <asm/tlb.h> | ||
21 | #include <asm/kvm_e500.h> | ||
22 | |||
23 | #define KVM_E500_TLB0_WAY_SIZE_BIT 7 /* Fixed */ | ||
24 | #define KVM_E500_TLB0_WAY_SIZE (1UL << KVM_E500_TLB0_WAY_SIZE_BIT) | ||
25 | #define KVM_E500_TLB0_WAY_SIZE_MASK (KVM_E500_TLB0_WAY_SIZE - 1) | ||
26 | |||
27 | #define KVM_E500_TLB0_WAY_NUM_BIT 1 /* No greater than 7 */ | ||
28 | #define KVM_E500_TLB0_WAY_NUM (1UL << KVM_E500_TLB0_WAY_NUM_BIT) | ||
29 | #define KVM_E500_TLB0_WAY_NUM_MASK (KVM_E500_TLB0_WAY_NUM - 1) | ||
30 | |||
31 | #define KVM_E500_TLB0_SIZE (KVM_E500_TLB0_WAY_SIZE * KVM_E500_TLB0_WAY_NUM) | ||
32 | #define KVM_E500_TLB1_SIZE 16 | ||
33 | |||
34 | #define index_of(tlbsel, esel) (((tlbsel) << 16) | ((esel) & 0xFFFF)) | ||
35 | #define tlbsel_of(index) ((index) >> 16) | ||
36 | #define esel_of(index) ((index) & 0xFFFF) | ||
37 | |||
38 | #define E500_TLB_USER_PERM_MASK (MAS3_UX|MAS3_UR|MAS3_UW) | ||
39 | #define E500_TLB_SUPER_PERM_MASK (MAS3_SX|MAS3_SR|MAS3_SW) | ||
40 | #define MAS2_ATTRIB_MASK \ | ||
41 | (MAS2_X0 | MAS2_X1) | ||
42 | #define MAS3_ATTRIB_MASK \ | ||
43 | (MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3 \ | ||
44 | | E500_TLB_USER_PERM_MASK | E500_TLB_SUPER_PERM_MASK) | ||
45 | |||
46 | extern void kvmppc_dump_tlbs(struct kvm_vcpu *); | ||
47 | extern int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *, ulong); | ||
48 | extern int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *); | ||
49 | extern int kvmppc_e500_emul_tlbre(struct kvm_vcpu *); | ||
50 | extern int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *, int, int); | ||
51 | extern int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *, int); | ||
52 | extern int kvmppc_e500_tlb_search(struct kvm_vcpu *, gva_t, unsigned int, int); | ||
53 | extern void kvmppc_e500_tlb_put(struct kvm_vcpu *); | ||
54 | extern void kvmppc_e500_tlb_load(struct kvm_vcpu *, int); | ||
55 | extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *); | ||
56 | extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *); | ||
57 | extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *); | ||
58 | |||
59 | /* TLB helper functions */ | ||
60 | static inline unsigned int get_tlb_size(const struct tlbe *tlbe) | ||
61 | { | ||
62 | return (tlbe->mas1 >> 8) & 0xf; | ||
63 | } | ||
64 | |||
65 | static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe) | ||
66 | { | ||
67 | return tlbe->mas2 & 0xfffff000; | ||
68 | } | ||
69 | |||
70 | static inline u64 get_tlb_bytes(const struct tlbe *tlbe) | ||
71 | { | ||
72 | unsigned int pgsize = get_tlb_size(tlbe); | ||
73 | return 1ULL << 10 << (pgsize << 1); | ||
74 | } | ||
75 | |||
76 | static inline gva_t get_tlb_end(const struct tlbe *tlbe) | ||
77 | { | ||
78 | u64 bytes = get_tlb_bytes(tlbe); | ||
79 | return get_tlb_eaddr(tlbe) + bytes - 1; | ||
80 | } | ||
81 | |||
82 | static inline u64 get_tlb_raddr(const struct tlbe *tlbe) | ||
83 | { | ||
84 | u64 rpn = tlbe->mas7; | ||
85 | return (rpn << 32) | (tlbe->mas3 & 0xfffff000); | ||
86 | } | ||
87 | |||
88 | static inline unsigned int get_tlb_tid(const struct tlbe *tlbe) | ||
89 | { | ||
90 | return (tlbe->mas1 >> 16) & 0xff; | ||
91 | } | ||
92 | |||
93 | static inline unsigned int get_tlb_ts(const struct tlbe *tlbe) | ||
94 | { | ||
95 | return (tlbe->mas1 >> 12) & 0x1; | ||
96 | } | ||
97 | |||
98 | static inline unsigned int get_tlb_v(const struct tlbe *tlbe) | ||
99 | { | ||
100 | return (tlbe->mas1 >> 31) & 0x1; | ||
101 | } | ||
102 | |||
103 | static inline unsigned int get_tlb_iprot(const struct tlbe *tlbe) | ||
104 | { | ||
105 | return (tlbe->mas1 >> 30) & 0x1; | ||
106 | } | ||
107 | |||
108 | static inline unsigned int get_cur_pid(struct kvm_vcpu *vcpu) | ||
109 | { | ||
110 | return vcpu->arch.pid & 0xff; | ||
111 | } | ||
112 | |||
113 | static inline unsigned int get_cur_spid( | ||
114 | const struct kvmppc_vcpu_e500 *vcpu_e500) | ||
115 | { | ||
116 | return (vcpu_e500->mas6 >> 16) & 0xff; | ||
117 | } | ||
118 | |||
119 | static inline unsigned int get_cur_sas( | ||
120 | const struct kvmppc_vcpu_e500 *vcpu_e500) | ||
121 | { | ||
122 | return vcpu_e500->mas6 & 0x1; | ||
123 | } | ||
124 | |||
125 | static inline unsigned int get_tlb_tlbsel( | ||
126 | const struct kvmppc_vcpu_e500 *vcpu_e500) | ||
127 | { | ||
128 | /* | ||
129 | * Manual says that tlbsel has 2 bits wide. | ||
130 | * Since we only have two TLBs, only lower bit is used. | ||
131 | */ | ||
132 | return (vcpu_e500->mas0 >> 28) & 0x1; | ||
133 | } | ||
134 | |||
135 | static inline unsigned int get_tlb_nv_bit( | ||
136 | const struct kvmppc_vcpu_e500 *vcpu_e500) | ||
137 | { | ||
138 | return vcpu_e500->mas0 & 0xfff; | ||
139 | } | ||
140 | |||
141 | static inline unsigned int get_tlb_esel_bit( | ||
142 | const struct kvmppc_vcpu_e500 *vcpu_e500) | ||
143 | { | ||
144 | return (vcpu_e500->mas0 >> 16) & 0xfff; | ||
145 | } | ||
146 | |||
147 | static inline unsigned int get_tlb_esel( | ||
148 | const struct kvmppc_vcpu_e500 *vcpu_e500, | ||
149 | int tlbsel) | ||
150 | { | ||
151 | unsigned int esel = get_tlb_esel_bit(vcpu_e500); | ||
152 | |||
153 | if (tlbsel == 0) { | ||
154 | esel &= KVM_E500_TLB0_WAY_NUM_MASK; | ||
155 | esel |= ((vcpu_e500->mas2 >> 12) & KVM_E500_TLB0_WAY_SIZE_MASK) | ||
156 | << KVM_E500_TLB0_WAY_NUM_BIT; | ||
157 | } else { | ||
158 | esel &= KVM_E500_TLB1_SIZE - 1; | ||
159 | } | ||
160 | |||
161 | return esel; | ||
162 | } | ||
163 | |||
164 | static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, | ||
165 | const struct tlbe *tlbe) | ||
166 | { | ||
167 | gpa_t gpa; | ||
168 | |||
169 | if (!get_tlb_v(tlbe)) | ||
170 | return 0; | ||
171 | |||
172 | /* Does it match current guest AS? */ | ||
173 | /* XXX what about IS != DS? */ | ||
174 | if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS)) | ||
175 | return 0; | ||
176 | |||
177 | gpa = get_tlb_raddr(tlbe); | ||
178 | if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT)) | ||
179 | /* Mapping is not for RAM. */ | ||
180 | return 0; | ||
181 | |||
182 | return 1; | ||
183 | } | ||
184 | |||
185 | #endif /* __KVM_E500_TLB_H__ */ | ||
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index d1d38daa93fb..a561d6e8da1c 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c | |||
@@ -30,6 +30,39 @@ | |||
30 | #include <asm/disassemble.h> | 30 | #include <asm/disassemble.h> |
31 | #include "timing.h" | 31 | #include "timing.h" |
32 | 32 | ||
33 | #define OP_TRAP 3 | ||
34 | |||
35 | #define OP_31_XOP_LWZX 23 | ||
36 | #define OP_31_XOP_LBZX 87 | ||
37 | #define OP_31_XOP_STWX 151 | ||
38 | #define OP_31_XOP_STBX 215 | ||
39 | #define OP_31_XOP_STBUX 247 | ||
40 | #define OP_31_XOP_LHZX 279 | ||
41 | #define OP_31_XOP_LHZUX 311 | ||
42 | #define OP_31_XOP_MFSPR 339 | ||
43 | #define OP_31_XOP_STHX 407 | ||
44 | #define OP_31_XOP_STHUX 439 | ||
45 | #define OP_31_XOP_MTSPR 467 | ||
46 | #define OP_31_XOP_DCBI 470 | ||
47 | #define OP_31_XOP_LWBRX 534 | ||
48 | #define OP_31_XOP_TLBSYNC 566 | ||
49 | #define OP_31_XOP_STWBRX 662 | ||
50 | #define OP_31_XOP_LHBRX 790 | ||
51 | #define OP_31_XOP_STHBRX 918 | ||
52 | |||
53 | #define OP_LWZ 32 | ||
54 | #define OP_LWZU 33 | ||
55 | #define OP_LBZ 34 | ||
56 | #define OP_LBZU 35 | ||
57 | #define OP_STW 36 | ||
58 | #define OP_STWU 37 | ||
59 | #define OP_STB 38 | ||
60 | #define OP_STBU 39 | ||
61 | #define OP_LHZ 40 | ||
62 | #define OP_LHZU 41 | ||
63 | #define OP_STH 44 | ||
64 | #define OP_STHU 45 | ||
65 | |||
33 | void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) | 66 | void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) |
34 | { | 67 | { |
35 | if (vcpu->arch.tcr & TCR_DIE) { | 68 | if (vcpu->arch.tcr & TCR_DIE) { |
@@ -78,7 +111,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
78 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); | 111 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); |
79 | 112 | ||
80 | switch (get_op(inst)) { | 113 | switch (get_op(inst)) { |
81 | case 3: /* trap */ | 114 | case OP_TRAP: |
82 | vcpu->arch.esr |= ESR_PTR; | 115 | vcpu->arch.esr |= ESR_PTR; |
83 | kvmppc_core_queue_program(vcpu); | 116 | kvmppc_core_queue_program(vcpu); |
84 | advance = 0; | 117 | advance = 0; |
@@ -87,31 +120,31 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
87 | case 31: | 120 | case 31: |
88 | switch (get_xop(inst)) { | 121 | switch (get_xop(inst)) { |
89 | 122 | ||
90 | case 23: /* lwzx */ | 123 | case OP_31_XOP_LWZX: |
91 | rt = get_rt(inst); | 124 | rt = get_rt(inst); |
92 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); | 125 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); |
93 | break; | 126 | break; |
94 | 127 | ||
95 | case 87: /* lbzx */ | 128 | case OP_31_XOP_LBZX: |
96 | rt = get_rt(inst); | 129 | rt = get_rt(inst); |
97 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | 130 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); |
98 | break; | 131 | break; |
99 | 132 | ||
100 | case 151: /* stwx */ | 133 | case OP_31_XOP_STWX: |
101 | rs = get_rs(inst); | 134 | rs = get_rs(inst); |
102 | emulated = kvmppc_handle_store(run, vcpu, | 135 | emulated = kvmppc_handle_store(run, vcpu, |
103 | vcpu->arch.gpr[rs], | 136 | vcpu->arch.gpr[rs], |
104 | 4, 1); | 137 | 4, 1); |
105 | break; | 138 | break; |
106 | 139 | ||
107 | case 215: /* stbx */ | 140 | case OP_31_XOP_STBX: |
108 | rs = get_rs(inst); | 141 | rs = get_rs(inst); |
109 | emulated = kvmppc_handle_store(run, vcpu, | 142 | emulated = kvmppc_handle_store(run, vcpu, |
110 | vcpu->arch.gpr[rs], | 143 | vcpu->arch.gpr[rs], |
111 | 1, 1); | 144 | 1, 1); |
112 | break; | 145 | break; |
113 | 146 | ||
114 | case 247: /* stbux */ | 147 | case OP_31_XOP_STBUX: |
115 | rs = get_rs(inst); | 148 | rs = get_rs(inst); |
116 | ra = get_ra(inst); | 149 | ra = get_ra(inst); |
117 | rb = get_rb(inst); | 150 | rb = get_rb(inst); |
@@ -126,12 +159,12 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
126 | vcpu->arch.gpr[rs] = ea; | 159 | vcpu->arch.gpr[rs] = ea; |
127 | break; | 160 | break; |
128 | 161 | ||
129 | case 279: /* lhzx */ | 162 | case OP_31_XOP_LHZX: |
130 | rt = get_rt(inst); | 163 | rt = get_rt(inst); |
131 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | 164 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); |
132 | break; | 165 | break; |
133 | 166 | ||
134 | case 311: /* lhzux */ | 167 | case OP_31_XOP_LHZUX: |
135 | rt = get_rt(inst); | 168 | rt = get_rt(inst); |
136 | ra = get_ra(inst); | 169 | ra = get_ra(inst); |
137 | rb = get_rb(inst); | 170 | rb = get_rb(inst); |
@@ -144,7 +177,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
144 | vcpu->arch.gpr[ra] = ea; | 177 | vcpu->arch.gpr[ra] = ea; |
145 | break; | 178 | break; |
146 | 179 | ||
147 | case 339: /* mfspr */ | 180 | case OP_31_XOP_MFSPR: |
148 | sprn = get_sprn(inst); | 181 | sprn = get_sprn(inst); |
149 | rt = get_rt(inst); | 182 | rt = get_rt(inst); |
150 | 183 | ||
@@ -185,7 +218,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
185 | } | 218 | } |
186 | break; | 219 | break; |
187 | 220 | ||
188 | case 407: /* sthx */ | 221 | case OP_31_XOP_STHX: |
189 | rs = get_rs(inst); | 222 | rs = get_rs(inst); |
190 | ra = get_ra(inst); | 223 | ra = get_ra(inst); |
191 | rb = get_rb(inst); | 224 | rb = get_rb(inst); |
@@ -195,7 +228,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
195 | 2, 1); | 228 | 2, 1); |
196 | break; | 229 | break; |
197 | 230 | ||
198 | case 439: /* sthux */ | 231 | case OP_31_XOP_STHUX: |
199 | rs = get_rs(inst); | 232 | rs = get_rs(inst); |
200 | ra = get_ra(inst); | 233 | ra = get_ra(inst); |
201 | rb = get_rb(inst); | 234 | rb = get_rb(inst); |
@@ -210,7 +243,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
210 | vcpu->arch.gpr[ra] = ea; | 243 | vcpu->arch.gpr[ra] = ea; |
211 | break; | 244 | break; |
212 | 245 | ||
213 | case 467: /* mtspr */ | 246 | case OP_31_XOP_MTSPR: |
214 | sprn = get_sprn(inst); | 247 | sprn = get_sprn(inst); |
215 | rs = get_rs(inst); | 248 | rs = get_rs(inst); |
216 | switch (sprn) { | 249 | switch (sprn) { |
@@ -246,7 +279,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
246 | } | 279 | } |
247 | break; | 280 | break; |
248 | 281 | ||
249 | case 470: /* dcbi */ | 282 | case OP_31_XOP_DCBI: |
250 | /* Do nothing. The guest is performing dcbi because | 283 | /* Do nothing. The guest is performing dcbi because |
251 | * hardware DMA is not snooped by the dcache, but | 284 | * hardware DMA is not snooped by the dcache, but |
252 | * emulated DMA either goes through the dcache as | 285 | * emulated DMA either goes through the dcache as |
@@ -254,15 +287,15 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
254 | * coherence. */ | 287 | * coherence. */ |
255 | break; | 288 | break; |
256 | 289 | ||
257 | case 534: /* lwbrx */ | 290 | case OP_31_XOP_LWBRX: |
258 | rt = get_rt(inst); | 291 | rt = get_rt(inst); |
259 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0); | 292 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0); |
260 | break; | 293 | break; |
261 | 294 | ||
262 | case 566: /* tlbsync */ | 295 | case OP_31_XOP_TLBSYNC: |
263 | break; | 296 | break; |
264 | 297 | ||
265 | case 662: /* stwbrx */ | 298 | case OP_31_XOP_STWBRX: |
266 | rs = get_rs(inst); | 299 | rs = get_rs(inst); |
267 | ra = get_ra(inst); | 300 | ra = get_ra(inst); |
268 | rb = get_rb(inst); | 301 | rb = get_rb(inst); |
@@ -272,12 +305,12 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
272 | 4, 0); | 305 | 4, 0); |
273 | break; | 306 | break; |
274 | 307 | ||
275 | case 790: /* lhbrx */ | 308 | case OP_31_XOP_LHBRX: |
276 | rt = get_rt(inst); | 309 | rt = get_rt(inst); |
277 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0); | 310 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0); |
278 | break; | 311 | break; |
279 | 312 | ||
280 | case 918: /* sthbrx */ | 313 | case OP_31_XOP_STHBRX: |
281 | rs = get_rs(inst); | 314 | rs = get_rs(inst); |
282 | ra = get_ra(inst); | 315 | ra = get_ra(inst); |
283 | rb = get_rb(inst); | 316 | rb = get_rb(inst); |
@@ -293,37 +326,37 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
293 | } | 326 | } |
294 | break; | 327 | break; |
295 | 328 | ||
296 | case 32: /* lwz */ | 329 | case OP_LWZ: |
297 | rt = get_rt(inst); | 330 | rt = get_rt(inst); |
298 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); | 331 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); |
299 | break; | 332 | break; |
300 | 333 | ||
301 | case 33: /* lwzu */ | 334 | case OP_LWZU: |
302 | ra = get_ra(inst); | 335 | ra = get_ra(inst); |
303 | rt = get_rt(inst); | 336 | rt = get_rt(inst); |
304 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); | 337 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); |
305 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | 338 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; |
306 | break; | 339 | break; |
307 | 340 | ||
308 | case 34: /* lbz */ | 341 | case OP_LBZ: |
309 | rt = get_rt(inst); | 342 | rt = get_rt(inst); |
310 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | 343 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); |
311 | break; | 344 | break; |
312 | 345 | ||
313 | case 35: /* lbzu */ | 346 | case OP_LBZU: |
314 | ra = get_ra(inst); | 347 | ra = get_ra(inst); |
315 | rt = get_rt(inst); | 348 | rt = get_rt(inst); |
316 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | 349 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); |
317 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | 350 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; |
318 | break; | 351 | break; |
319 | 352 | ||
320 | case 36: /* stw */ | 353 | case OP_STW: |
321 | rs = get_rs(inst); | 354 | rs = get_rs(inst); |
322 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | 355 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], |
323 | 4, 1); | 356 | 4, 1); |
324 | break; | 357 | break; |
325 | 358 | ||
326 | case 37: /* stwu */ | 359 | case OP_STWU: |
327 | ra = get_ra(inst); | 360 | ra = get_ra(inst); |
328 | rs = get_rs(inst); | 361 | rs = get_rs(inst); |
329 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | 362 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], |
@@ -331,13 +364,13 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
331 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | 364 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; |
332 | break; | 365 | break; |
333 | 366 | ||
334 | case 38: /* stb */ | 367 | case OP_STB: |
335 | rs = get_rs(inst); | 368 | rs = get_rs(inst); |
336 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | 369 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], |
337 | 1, 1); | 370 | 1, 1); |
338 | break; | 371 | break; |
339 | 372 | ||
340 | case 39: /* stbu */ | 373 | case OP_STBU: |
341 | ra = get_ra(inst); | 374 | ra = get_ra(inst); |
342 | rs = get_rs(inst); | 375 | rs = get_rs(inst); |
343 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | 376 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], |
@@ -345,25 +378,25 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
345 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | 378 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; |
346 | break; | 379 | break; |
347 | 380 | ||
348 | case 40: /* lhz */ | 381 | case OP_LHZ: |
349 | rt = get_rt(inst); | 382 | rt = get_rt(inst); |
350 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | 383 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); |
351 | break; | 384 | break; |
352 | 385 | ||
353 | case 41: /* lhzu */ | 386 | case OP_LHZU: |
354 | ra = get_ra(inst); | 387 | ra = get_ra(inst); |
355 | rt = get_rt(inst); | 388 | rt = get_rt(inst); |
356 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | 389 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); |
357 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | 390 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; |
358 | break; | 391 | break; |
359 | 392 | ||
360 | case 44: /* sth */ | 393 | case OP_STH: |
361 | rs = get_rs(inst); | 394 | rs = get_rs(inst); |
362 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | 395 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], |
363 | 2, 1); | 396 | 2, 1); |
364 | break; | 397 | break; |
365 | 398 | ||
366 | case 45: /* sthu */ | 399 | case OP_STHU: |
367 | ra = get_ra(inst); | 400 | ra = get_ra(inst); |
368 | rs = get_rs(inst); | 401 | rs = get_rs(inst); |
369 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | 402 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], |
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 5f81256287f5..9057335fdc61 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -216,46 +216,23 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | |||
216 | 216 | ||
217 | void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) | 217 | void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) |
218 | { | 218 | { |
219 | kvmppc_core_destroy_mmu(vcpu); | 219 | kvmppc_mmu_destroy(vcpu); |
220 | } | 220 | } |
221 | 221 | ||
222 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | 222 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) |
223 | { | 223 | { |
224 | if (vcpu->guest_debug.enabled) | ||
225 | kvmppc_core_load_guest_debugstate(vcpu); | ||
226 | |||
227 | kvmppc_core_vcpu_load(vcpu, cpu); | 224 | kvmppc_core_vcpu_load(vcpu, cpu); |
228 | } | 225 | } |
229 | 226 | ||
230 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | 227 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) |
231 | { | 228 | { |
232 | if (vcpu->guest_debug.enabled) | ||
233 | kvmppc_core_load_host_debugstate(vcpu); | ||
234 | |||
235 | /* Don't leave guest TLB entries resident when being de-scheduled. */ | ||
236 | /* XXX It would be nice to differentiate between heavyweight exit and | ||
237 | * sched_out here, since we could avoid the TLB flush for heavyweight | ||
238 | * exits. */ | ||
239 | _tlbil_all(); | ||
240 | kvmppc_core_vcpu_put(vcpu); | 229 | kvmppc_core_vcpu_put(vcpu); |
241 | } | 230 | } |
242 | 231 | ||
243 | int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, | 232 | int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, |
244 | struct kvm_debug_guest *dbg) | 233 | struct kvm_guest_debug *dbg) |
245 | { | 234 | { |
246 | int i; | 235 | return -EINVAL; |
247 | |||
248 | vcpu->guest_debug.enabled = dbg->enabled; | ||
249 | if (vcpu->guest_debug.enabled) { | ||
250 | for (i=0; i < ARRAY_SIZE(vcpu->guest_debug.bp); i++) { | ||
251 | if (dbg->breakpoints[i].enabled) | ||
252 | vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address; | ||
253 | else | ||
254 | vcpu->guest_debug.bp[i] = 0; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | 236 | } |
260 | 237 | ||
261 | static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, | 238 | static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, |
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 28c04dab2633..882e47080e74 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -237,8 +237,6 @@ extern int noirqdebug; | |||
237 | 237 | ||
238 | static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) | 238 | static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) |
239 | { | 239 | { |
240 | const unsigned int cpu = smp_processor_id(); | ||
241 | |||
242 | spin_lock(&desc->lock); | 240 | spin_lock(&desc->lock); |
243 | 241 | ||
244 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | 242 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); |
@@ -254,7 +252,7 @@ static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) | |||
254 | goto out_eoi; | 252 | goto out_eoi; |
255 | } | 253 | } |
256 | 254 | ||
257 | kstat_cpu(cpu).irqs[irq]++; | 255 | kstat_incr_irqs_this_cpu(irq, desc); |
258 | 256 | ||
259 | /* Mark the IRQ currently in progress.*/ | 257 | /* Mark the IRQ currently in progress.*/ |
260 | desc->status |= IRQ_INPROGRESS; | 258 | desc->status |= IRQ_INPROGRESS; |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 6a0ad196aeb3..f085369301b1 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -508,7 +508,7 @@ static void __spu_add_to_rq(struct spu_context *ctx) | |||
508 | list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); | 508 | list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); |
509 | set_bit(ctx->prio, spu_prio->bitmap); | 509 | set_bit(ctx->prio, spu_prio->bitmap); |
510 | if (!spu_prio->nr_waiting++) | 510 | if (!spu_prio->nr_waiting++) |
511 | __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); | 511 | mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); |
512 | } | 512 | } |
513 | } | 513 | } |
514 | 514 | ||
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 58311a867851..a705fffbb498 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c | |||
@@ -376,7 +376,7 @@ static int ps3_system_bus_probe(struct device *_dev) | |||
376 | struct ps3_system_bus_driver *drv; | 376 | struct ps3_system_bus_driver *drv; |
377 | 377 | ||
378 | BUG_ON(!dev); | 378 | BUG_ON(!dev); |
379 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); | 379 | dev_dbg(_dev, "%s:%d\n", __func__, __LINE__); |
380 | 380 | ||
381 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | 381 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); |
382 | BUG_ON(!drv); | 382 | BUG_ON(!drv); |
@@ -398,7 +398,7 @@ static int ps3_system_bus_remove(struct device *_dev) | |||
398 | struct ps3_system_bus_driver *drv; | 398 | struct ps3_system_bus_driver *drv; |
399 | 399 | ||
400 | BUG_ON(!dev); | 400 | BUG_ON(!dev); |
401 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); | 401 | dev_dbg(_dev, "%s:%d\n", __func__, __LINE__); |
402 | 402 | ||
403 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | 403 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); |
404 | BUG_ON(!drv); | 404 | BUG_ON(!drv); |
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 84e058f1e1cc..80b513449f4c 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -153,9 +153,10 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) | |||
153 | { | 153 | { |
154 | int server; | 154 | int server; |
155 | /* For the moment only implement delivery to all cpus or one cpu */ | 155 | /* For the moment only implement delivery to all cpus or one cpu */ |
156 | cpumask_t cpumask = irq_desc[virq].affinity; | 156 | cpumask_t cpumask; |
157 | cpumask_t tmp = CPU_MASK_NONE; | 157 | cpumask_t tmp = CPU_MASK_NONE; |
158 | 158 | ||
159 | cpumask_copy(&cpumask, irq_desc[virq].affinity); | ||
159 | if (!distribute_irqs) | 160 | if (!distribute_irqs) |
160 | return default_server; | 161 | return default_server; |
161 | 162 | ||
@@ -869,7 +870,7 @@ void xics_migrate_irqs_away(void) | |||
869 | virq, cpu); | 870 | virq, cpu); |
870 | 871 | ||
871 | /* Reset affinity to all cpus */ | 872 | /* Reset affinity to all cpus */ |
872 | irq_desc[virq].affinity = CPU_MASK_ALL; | 873 | cpumask_setall(irq_desc[virq].affinity); |
873 | desc->chip->set_affinity(virq, cpu_all_mask); | 874 | desc->chip->set_affinity(virq, cpu_all_mask); |
874 | unlock: | 875 | unlock: |
875 | spin_unlock_irqrestore(&desc->lock, flags); | 876 | spin_unlock_irqrestore(&desc->lock, flags); |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index a35297dbac28..532e205303a2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -566,9 +566,10 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) | |||
566 | #ifdef CONFIG_SMP | 566 | #ifdef CONFIG_SMP |
567 | static int irq_choose_cpu(unsigned int virt_irq) | 567 | static int irq_choose_cpu(unsigned int virt_irq) |
568 | { | 568 | { |
569 | cpumask_t mask = irq_desc[virt_irq].affinity; | 569 | cpumask_t mask; |
570 | int cpuid; | 570 | int cpuid; |
571 | 571 | ||
572 | cpumask_copy(&mask, irq_desc[virt_irq].affinity); | ||
572 | if (cpus_equal(mask, CPU_MASK_ALL)) { | 573 | if (cpus_equal(mask, CPU_MASK_ALL)) { |
573 | static int irq_rover; | 574 | static int irq_rover; |
574 | static DEFINE_SPINLOCK(irq_rover_lock); | 575 | static DEFINE_SPINLOCK(irq_rover_lock); |