1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | |
3 | #include <asm/kvm_ppc.h> |
4 | #include <asm/pmc.h> |
5 | |
6 | #include "book3s_hv.h" |
7 | |
8 | static void freeze_pmu(unsigned long mmcr0, unsigned long mmcra) |
9 | { |
10 | if (!(mmcr0 & MMCR0_FC)) |
11 | goto do_freeze; |
12 | if (mmcra & MMCRA_SAMPLE_ENABLE) |
13 | goto do_freeze; |
14 | if (cpu_has_feature(CPU_FTR_ARCH_31)) { |
15 | if (!(mmcr0 & MMCR0_PMCCEXT)) |
16 | goto do_freeze; |
17 | if (!(mmcra & MMCRA_BHRB_DISABLE)) |
18 | goto do_freeze; |
19 | } |
20 | return; |
21 | |
22 | do_freeze: |
23 | mmcr0 = MMCR0_FC; |
24 | mmcra = 0; |
25 | if (cpu_has_feature(CPU_FTR_ARCH_31)) { |
26 | mmcr0 |= MMCR0_PMCCEXT; |
27 | mmcra = MMCRA_BHRB_DISABLE; |
28 | } |
29 | |
30 | mtspr(SPRN_MMCR0, mmcr0); |
31 | mtspr(SPRN_MMCRA, mmcra); |
32 | isync(); |
33 | } |
34 | |
35 | void switch_pmu_to_guest(struct kvm_vcpu *vcpu, |
36 | struct p9_host_os_sprs *host_os_sprs) |
37 | { |
38 | struct lppaca *lp; |
39 | int load_pmu = 1; |
40 | |
41 | lp = vcpu->arch.vpa.pinned_addr; |
42 | if (lp) |
43 | load_pmu = lp->pmcregs_in_use; |
44 | |
45 | /* Save host */ |
46 | if (ppc_get_pmu_inuse()) { |
47 | /* POWER9, POWER10 do not implement HPMC or SPMC */ |
48 | |
49 | host_os_sprs->mmcr0 = mfspr(SPRN_MMCR0); |
50 | host_os_sprs->mmcra = mfspr(SPRN_MMCRA); |
51 | |
52 | freeze_pmu(mmcr0: host_os_sprs->mmcr0, mmcra: host_os_sprs->mmcra); |
53 | |
54 | host_os_sprs->pmc1 = mfspr(SPRN_PMC1); |
55 | host_os_sprs->pmc2 = mfspr(SPRN_PMC2); |
56 | host_os_sprs->pmc3 = mfspr(SPRN_PMC3); |
57 | host_os_sprs->pmc4 = mfspr(SPRN_PMC4); |
58 | host_os_sprs->pmc5 = mfspr(SPRN_PMC5); |
59 | host_os_sprs->pmc6 = mfspr(SPRN_PMC6); |
60 | host_os_sprs->mmcr1 = mfspr(SPRN_MMCR1); |
61 | host_os_sprs->mmcr2 = mfspr(SPRN_MMCR2); |
62 | host_os_sprs->sdar = mfspr(SPRN_SDAR); |
63 | host_os_sprs->siar = mfspr(SPRN_SIAR); |
64 | host_os_sprs->sier1 = mfspr(SPRN_SIER); |
65 | |
66 | if (cpu_has_feature(CPU_FTR_ARCH_31)) { |
67 | host_os_sprs->mmcr3 = mfspr(SPRN_MMCR3); |
68 | host_os_sprs->sier2 = mfspr(SPRN_SIER2); |
69 | host_os_sprs->sier3 = mfspr(SPRN_SIER3); |
70 | } |
71 | } |
72 | |
73 | #ifdef CONFIG_PPC_PSERIES |
74 | /* After saving PMU, before loading guest PMU, flip pmcregs_in_use */ |
75 | if (kvmhv_on_pseries()) { |
76 | barrier(); |
77 | get_lppaca()->pmcregs_in_use = load_pmu; |
78 | barrier(); |
79 | } |
80 | #endif |
81 | |
82 | /* |
83 | * Load guest. If the VPA said the PMCs are not in use but the guest |
84 | * tried to access them anyway, HFSCR[PM] will be set by the HFAC |
85 | * fault so we can make forward progress. |
86 | */ |
87 | if (load_pmu || (vcpu->arch.hfscr & HFSCR_PM)) { |
88 | mtspr(SPRN_PMC1, vcpu->arch.pmc[0]); |
89 | mtspr(SPRN_PMC2, vcpu->arch.pmc[1]); |
90 | mtspr(SPRN_PMC3, vcpu->arch.pmc[2]); |
91 | mtspr(SPRN_PMC4, vcpu->arch.pmc[3]); |
92 | mtspr(SPRN_PMC5, vcpu->arch.pmc[4]); |
93 | mtspr(SPRN_PMC6, vcpu->arch.pmc[5]); |
94 | mtspr(SPRN_MMCR1, vcpu->arch.mmcr[1]); |
95 | mtspr(SPRN_MMCR2, vcpu->arch.mmcr[2]); |
96 | mtspr(SPRN_SDAR, vcpu->arch.sdar); |
97 | mtspr(SPRN_SIAR, vcpu->arch.siar); |
98 | mtspr(SPRN_SIER, vcpu->arch.sier[0]); |
99 | |
100 | if (cpu_has_feature(CPU_FTR_ARCH_31)) { |
101 | mtspr(SPRN_MMCR3, vcpu->arch.mmcr[3]); |
102 | mtspr(SPRN_SIER2, vcpu->arch.sier[1]); |
103 | mtspr(SPRN_SIER3, vcpu->arch.sier[2]); |
104 | } |
105 | |
106 | /* Set MMCRA then MMCR0 last */ |
107 | mtspr(SPRN_MMCRA, vcpu->arch.mmcra); |
108 | mtspr(SPRN_MMCR0, vcpu->arch.mmcr[0]); |
109 | /* No isync necessary because we're starting counters */ |
110 | |
111 | if (!vcpu->arch.nested && |
112 | (vcpu->arch.hfscr_permitted & HFSCR_PM)) |
113 | vcpu->arch.hfscr |= HFSCR_PM; |
114 | } |
115 | } |
116 | EXPORT_SYMBOL_GPL(switch_pmu_to_guest); |
117 | |
118 | void switch_pmu_to_host(struct kvm_vcpu *vcpu, |
119 | struct p9_host_os_sprs *host_os_sprs) |
120 | { |
121 | struct lppaca *lp; |
122 | int save_pmu = 1; |
123 | |
124 | lp = vcpu->arch.vpa.pinned_addr; |
125 | if (lp) |
126 | save_pmu = lp->pmcregs_in_use; |
127 | if (IS_ENABLED(CONFIG_KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND)) { |
128 | /* |
129 | * Save pmu if this guest is capable of running nested guests. |
130 | * This is option is for old L1s that do not set their |
131 | * lppaca->pmcregs_in_use properly when entering their L2. |
132 | */ |
133 | save_pmu |= nesting_enabled(vcpu->kvm); |
134 | } |
135 | |
136 | if (save_pmu) { |
137 | vcpu->arch.mmcr[0] = mfspr(SPRN_MMCR0); |
138 | vcpu->arch.mmcra = mfspr(SPRN_MMCRA); |
139 | |
140 | freeze_pmu(mmcr0: vcpu->arch.mmcr[0], mmcra: vcpu->arch.mmcra); |
141 | |
142 | vcpu->arch.pmc[0] = mfspr(SPRN_PMC1); |
143 | vcpu->arch.pmc[1] = mfspr(SPRN_PMC2); |
144 | vcpu->arch.pmc[2] = mfspr(SPRN_PMC3); |
145 | vcpu->arch.pmc[3] = mfspr(SPRN_PMC4); |
146 | vcpu->arch.pmc[4] = mfspr(SPRN_PMC5); |
147 | vcpu->arch.pmc[5] = mfspr(SPRN_PMC6); |
148 | vcpu->arch.mmcr[1] = mfspr(SPRN_MMCR1); |
149 | vcpu->arch.mmcr[2] = mfspr(SPRN_MMCR2); |
150 | vcpu->arch.sdar = mfspr(SPRN_SDAR); |
151 | vcpu->arch.siar = mfspr(SPRN_SIAR); |
152 | vcpu->arch.sier[0] = mfspr(SPRN_SIER); |
153 | |
154 | if (cpu_has_feature(CPU_FTR_ARCH_31)) { |
155 | vcpu->arch.mmcr[3] = mfspr(SPRN_MMCR3); |
156 | vcpu->arch.sier[1] = mfspr(SPRN_SIER2); |
157 | vcpu->arch.sier[2] = mfspr(SPRN_SIER3); |
158 | } |
159 | |
160 | } else if (vcpu->arch.hfscr & HFSCR_PM) { |
161 | /* |
162 | * The guest accessed PMC SPRs without specifying they should |
163 | * be preserved, or it cleared pmcregs_in_use after the last |
164 | * access. Just ensure they are frozen. |
165 | */ |
166 | freeze_pmu(mfspr(SPRN_MMCR0), mfspr(SPRN_MMCRA)); |
167 | |
168 | /* |
169 | * Demand-fault PMU register access in the guest. |
170 | * |
171 | * This is used to grab the guest's VPA pmcregs_in_use value |
172 | * and reflect it into the host's VPA in the case of a nested |
173 | * hypervisor. |
174 | * |
175 | * It also avoids having to zero-out SPRs after each guest |
176 | * exit to avoid side-channels when. |
177 | * |
178 | * This is cleared here when we exit the guest, so later HFSCR |
179 | * interrupt handling can add it back to run the guest with |
180 | * PM enabled next time. |
181 | */ |
182 | if (!vcpu->arch.nested) |
183 | vcpu->arch.hfscr &= ~HFSCR_PM; |
184 | } /* otherwise the PMU should still be frozen */ |
185 | |
186 | #ifdef CONFIG_PPC_PSERIES |
187 | if (kvmhv_on_pseries()) { |
188 | barrier(); |
189 | get_lppaca()->pmcregs_in_use = ppc_get_pmu_inuse(); |
190 | barrier(); |
191 | } |
192 | #endif |
193 | |
194 | if (ppc_get_pmu_inuse()) { |
195 | mtspr(SPRN_PMC1, host_os_sprs->pmc1); |
196 | mtspr(SPRN_PMC2, host_os_sprs->pmc2); |
197 | mtspr(SPRN_PMC3, host_os_sprs->pmc3); |
198 | mtspr(SPRN_PMC4, host_os_sprs->pmc4); |
199 | mtspr(SPRN_PMC5, host_os_sprs->pmc5); |
200 | mtspr(SPRN_PMC6, host_os_sprs->pmc6); |
201 | mtspr(SPRN_MMCR1, host_os_sprs->mmcr1); |
202 | mtspr(SPRN_MMCR2, host_os_sprs->mmcr2); |
203 | mtspr(SPRN_SDAR, host_os_sprs->sdar); |
204 | mtspr(SPRN_SIAR, host_os_sprs->siar); |
205 | mtspr(SPRN_SIER, host_os_sprs->sier1); |
206 | |
207 | if (cpu_has_feature(CPU_FTR_ARCH_31)) { |
208 | mtspr(SPRN_MMCR3, host_os_sprs->mmcr3); |
209 | mtspr(SPRN_SIER2, host_os_sprs->sier2); |
210 | mtspr(SPRN_SIER3, host_os_sprs->sier3); |
211 | } |
212 | |
213 | /* Set MMCRA then MMCR0 last */ |
214 | mtspr(SPRN_MMCRA, host_os_sprs->mmcra); |
215 | mtspr(SPRN_MMCR0, host_os_sprs->mmcr0); |
216 | isync(); |
217 | } |
218 | } |
219 | EXPORT_SYMBOL_GPL(switch_pmu_to_host); |
220 | |