Commit | Line | Data |
---|---|---|
e39c5add ZW |
1 | /* |
2 | * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
21 | * SOFTWARE. | |
22 | * | |
23 | * Authors: | |
24 | * Ke Yu | |
25 | * Kevin Tian <kevin.tian@intel.com> | |
26 | * Dexuan Cui | |
27 | * | |
28 | * Contributors: | |
29 | * Tina Zhang <tina.zhang@intel.com> | |
30 | * Min He <min.he@intel.com> | |
31 | * Niu Bing <bing.niu@intel.com> | |
32 | * Zhi Wang <zhi.a.wang@intel.com> | |
33 | * | |
34 | */ | |
35 | ||
36 | #include "i915_drv.h" | |
feddf6e8 | 37 | #include "gvt.h" |
e39c5add ZW |
38 | |
39 | /** | |
40 | * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset | |
41 | * @vgpu: a vGPU | |
42 | * | |
43 | * Returns: | |
44 | * Zero on success, negative error code if failed | |
45 | */ | |
46 | int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) | |
47 | { | |
f090a00d | 48 | u64 gttmmio_gpa = intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0); |
e39c5add ZW |
49 | return gpa - gttmmio_gpa; |
50 | } | |
51 | ||
52 | #define reg_is_mmio(gvt, reg) \ | |
53 | (reg >= 0 && reg < gvt->device_info.mmio_size) | |
54 | ||
55 | #define reg_is_gtt(gvt, reg) \ | |
56 | (reg >= gvt->device_info.gtt_start_offset \ | |
57 | && reg < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) | |
58 | ||
fd64be63 MH |
59 | static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, uint64_t pa, |
60 | void *p_data, unsigned int bytes, bool read) | |
61 | { | |
62 | struct intel_gvt *gvt = NULL; | |
63 | void *pt = NULL; | |
64 | unsigned int offset = 0; | |
65 | ||
66 | if (!vgpu || !p_data) | |
67 | return; | |
68 | ||
69 | gvt = vgpu->gvt; | |
70 | mutex_lock(&gvt->lock); | |
71 | offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); | |
72 | if (reg_is_mmio(gvt, offset)) { | |
73 | if (read) | |
74 | intel_vgpu_default_mmio_read(vgpu, offset, p_data, | |
75 | bytes); | |
76 | else | |
77 | intel_vgpu_default_mmio_write(vgpu, offset, p_data, | |
78 | bytes); | |
ede9d0cf | 79 | } else if (reg_is_gtt(gvt, offset)) { |
fd64be63 | 80 | offset -= gvt->device_info.gtt_start_offset; |
ede9d0cf | 81 | pt = vgpu->gtt.ggtt_mm->ggtt_mm.virtual_ggtt + offset; |
fd64be63 MH |
82 | if (read) |
83 | memcpy(p_data, pt, bytes); | |
84 | else | |
85 | memcpy(pt, p_data, bytes); | |
86 | ||
fd64be63 MH |
87 | } |
88 | mutex_unlock(&gvt->lock); | |
89 | } | |
90 | ||
e39c5add ZW |
91 | /** |
92 | * intel_vgpu_emulate_mmio_read - emulate MMIO read | |
93 | * @vgpu: a vGPU | |
94 | * @pa: guest physical address | |
95 | * @p_data: data return buffer | |
96 | * @bytes: access data length | |
97 | * | |
98 | * Returns: | |
99 | * Zero on success, negative error code if failed | |
100 | */ | |
9ec1e66b | 101 | int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa, |
e39c5add ZW |
102 | void *p_data, unsigned int bytes) |
103 | { | |
e39c5add | 104 | struct intel_gvt *gvt = vgpu->gvt; |
e39c5add ZW |
105 | unsigned int offset = 0; |
106 | int ret = -EINVAL; | |
107 | ||
fd64be63 MH |
108 | if (vgpu->failsafe) { |
109 | failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, true); | |
110 | return 0; | |
111 | } | |
e39c5add ZW |
112 | mutex_lock(&gvt->lock); |
113 | ||
e39c5add ZW |
114 | offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); |
115 | ||
116 | if (WARN_ON(bytes > 8)) | |
117 | goto err; | |
118 | ||
119 | if (reg_is_gtt(gvt, offset)) { | |
120 | if (WARN_ON(!IS_ALIGNED(offset, 4) && !IS_ALIGNED(offset, 8))) | |
121 | goto err; | |
122 | if (WARN_ON(bytes != 4 && bytes != 8)) | |
123 | goto err; | |
124 | if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1))) | |
125 | goto err; | |
126 | ||
a143cef7 | 127 | ret = intel_vgpu_emulate_ggtt_mmio_read(vgpu, offset, |
e39c5add ZW |
128 | p_data, bytes); |
129 | if (ret) | |
130 | goto err; | |
eb3f0517 | 131 | goto out; |
e39c5add ZW |
132 | } |
133 | ||
134 | if (WARN_ON_ONCE(!reg_is_mmio(gvt, offset))) { | |
135 | ret = intel_gvt_hypervisor_read_gpa(vgpu, pa, p_data, bytes); | |
eb3f0517 | 136 | goto out; |
e39c5add ZW |
137 | } |
138 | ||
139 | if (WARN_ON(!reg_is_mmio(gvt, offset + bytes - 1))) | |
140 | goto err; | |
141 | ||
e39c5add ZW |
142 | if (!intel_gvt_mmio_is_unalign(gvt, offset)) { |
143 | if (WARN_ON(!IS_ALIGNED(offset, bytes))) | |
144 | goto err; | |
145 | } | |
146 | ||
65f9f6fe CD |
147 | ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, true); |
148 | if (ret < 0) | |
e39c5add ZW |
149 | goto err; |
150 | ||
151 | intel_gvt_mmio_set_accessed(gvt, offset); | |
eb3f0517 PZ |
152 | ret = 0; |
153 | goto out; | |
154 | ||
e39c5add | 155 | err: |
695fbc08 TZ |
156 | gvt_vgpu_err("fail to emulate MMIO read %08x len %d\n", |
157 | offset, bytes); | |
eb3f0517 | 158 | out: |
e39c5add ZW |
159 | mutex_unlock(&gvt->lock); |
160 | return ret; | |
161 | } | |
162 | ||
163 | /** | |
164 | * intel_vgpu_emulate_mmio_write - emulate MMIO write | |
165 | * @vgpu: a vGPU | |
166 | * @pa: guest physical address | |
167 | * @p_data: write data buffer | |
168 | * @bytes: access data length | |
169 | * | |
170 | * Returns: | |
171 | * Zero on success, negative error code if failed | |
172 | */ | |
9ec1e66b | 173 | int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa, |
e39c5add ZW |
174 | void *p_data, unsigned int bytes) |
175 | { | |
e39c5add | 176 | struct intel_gvt *gvt = vgpu->gvt; |
e39c5add | 177 | unsigned int offset = 0; |
e39c5add ZW |
178 | int ret = -EINVAL; |
179 | ||
fd64be63 MH |
180 | if (vgpu->failsafe) { |
181 | failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, false); | |
182 | return 0; | |
183 | } | |
184 | ||
e39c5add ZW |
185 | mutex_lock(&gvt->lock); |
186 | ||
e39c5add ZW |
187 | offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); |
188 | ||
189 | if (WARN_ON(bytes > 8)) | |
190 | goto err; | |
191 | ||
192 | if (reg_is_gtt(gvt, offset)) { | |
193 | if (WARN_ON(!IS_ALIGNED(offset, 4) && !IS_ALIGNED(offset, 8))) | |
194 | goto err; | |
195 | if (WARN_ON(bytes != 4 && bytes != 8)) | |
196 | goto err; | |
197 | if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1))) | |
198 | goto err; | |
199 | ||
a143cef7 | 200 | ret = intel_vgpu_emulate_ggtt_mmio_write(vgpu, offset, |
e39c5add ZW |
201 | p_data, bytes); |
202 | if (ret) | |
203 | goto err; | |
eb3f0517 | 204 | goto out; |
e39c5add ZW |
205 | } |
206 | ||
207 | if (WARN_ON_ONCE(!reg_is_mmio(gvt, offset))) { | |
208 | ret = intel_gvt_hypervisor_write_gpa(vgpu, pa, p_data, bytes); | |
eb3f0517 | 209 | goto out; |
e39c5add ZW |
210 | } |
211 | ||
65f9f6fe CD |
212 | ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, false); |
213 | if (ret < 0) | |
e39c5add | 214 | goto err; |
65f9f6fe | 215 | |
e39c5add | 216 | intel_gvt_mmio_set_accessed(gvt, offset); |
eb3f0517 PZ |
217 | ret = 0; |
218 | goto out; | |
e39c5add | 219 | err: |
695fbc08 TZ |
220 | gvt_vgpu_err("fail to emulate MMIO write %08x len %d\n", offset, |
221 | bytes); | |
eb3f0517 | 222 | out: |
e39c5add ZW |
223 | mutex_unlock(&gvt->lock); |
224 | return ret; | |
225 | } | |
cdcc4347 | 226 | |
97d58f7d CD |
227 | |
228 | /** | |
229 | * intel_vgpu_reset_mmio - reset virtual MMIO space | |
230 | * @vgpu: a vGPU | |
231 | * | |
232 | */ | |
615c16a9 | 233 | void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr) |
97d58f7d CD |
234 | { |
235 | struct intel_gvt *gvt = vgpu->gvt; | |
236 | const struct intel_gvt_device_info *info = &gvt->device_info; | |
615c16a9 | 237 | void *mmio = gvt->firmware.mmio; |
97d58f7d | 238 | |
615c16a9 | 239 | if (dmlr) { |
240 | memcpy(vgpu->mmio.vreg, mmio, info->mmio_size); | |
241 | memcpy(vgpu->mmio.sreg, mmio, info->mmio_size); | |
97d58f7d | 242 | |
90551a12 | 243 | vgpu_vreg_t(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0; |
97d58f7d | 244 | |
615c16a9 | 245 | /* set the bit 0:2(Core C-State ) to C0 */ |
90551a12 | 246 | vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0; |
615c16a9 | 247 | } else { |
248 | #define GVT_GEN8_MMIO_RESET_OFFSET (0x44200) | |
249 | /* only reset the engine related, so starting with 0x44200 | |
250 | * interrupt include DE,display mmio related will not be | |
251 | * touched | |
252 | */ | |
253 | memcpy(vgpu->mmio.vreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); | |
254 | memcpy(vgpu->mmio.sreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); | |
255 | } | |
d1be371d | 256 | |
97d58f7d CD |
257 | } |
258 | ||
cdcc4347 CD |
259 | /** |
260 | * intel_vgpu_init_mmio - init MMIO space | |
261 | * @vgpu: a vGPU | |
262 | * | |
263 | * Returns: | |
264 | * Zero on success, negative error code if failed | |
265 | */ | |
266 | int intel_vgpu_init_mmio(struct intel_vgpu *vgpu) | |
267 | { | |
268 | const struct intel_gvt_device_info *info = &vgpu->gvt->device_info; | |
269 | ||
fad953ce | 270 | vgpu->mmio.vreg = vzalloc(array_size(info->mmio_size, 2)); |
97d58f7d CD |
271 | if (!vgpu->mmio.vreg) |
272 | return -ENOMEM; | |
cdcc4347 | 273 | |
97d58f7d | 274 | vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size; |
cdcc4347 | 275 | |
615c16a9 | 276 | intel_vgpu_reset_mmio(vgpu, true); |
cdcc4347 CD |
277 | |
278 | return 0; | |
279 | } | |
280 | ||
281 | /** | |
282 | * intel_vgpu_clean_mmio - clean MMIO space | |
283 | * @vgpu: a vGPU | |
284 | * | |
285 | */ | |
286 | void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu) | |
287 | { | |
288 | vfree(vgpu->mmio.vreg); | |
289 | vgpu->mmio.vreg = vgpu->mmio.sreg = NULL; | |
290 | } |