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" |
37 | #include "i915_reg.h" |
38 | #include "gvt.h" |
39 | |
40 | #include "display/intel_dpio_phy.h" |
41 | #include "gt/intel_gt_regs.h" |
42 | |
43 | /** |
44 | * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset |
45 | * @vgpu: a vGPU |
46 | * @gpa: guest physical address |
47 | * |
48 | * Returns: |
49 | * Zero on success, negative error code if failed |
50 | */ |
51 | int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) |
52 | { |
53 | u64 gttmmio_gpa = intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0); |
54 | return gpa - gttmmio_gpa; |
55 | } |
56 | |
57 | #define reg_is_mmio(gvt, reg) \ |
58 | (reg >= 0 && reg < gvt->device_info.mmio_size) |
59 | |
60 | #define reg_is_gtt(gvt, reg) \ |
61 | (reg >= gvt->device_info.gtt_start_offset \ |
62 | && reg < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) |
63 | |
64 | static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, u64 pa, |
65 | void *p_data, unsigned int bytes, bool read) |
66 | { |
67 | struct intel_gvt *gvt = NULL; |
68 | void *pt = NULL; |
69 | unsigned int offset = 0; |
70 | |
71 | if (!vgpu || !p_data) |
72 | return; |
73 | |
74 | gvt = vgpu->gvt; |
75 | mutex_lock(&vgpu->vgpu_lock); |
76 | offset = intel_vgpu_gpa_to_mmio_offset(vgpu, gpa: pa); |
77 | if (reg_is_mmio(gvt, offset)) { |
78 | if (read) |
79 | intel_vgpu_default_mmio_read(vgpu, offset, p_data, |
80 | bytes); |
81 | else |
82 | intel_vgpu_default_mmio_write(vgpu, offset, p_data, |
83 | bytes); |
84 | } else if (reg_is_gtt(gvt, offset)) { |
85 | offset -= gvt->device_info.gtt_start_offset; |
86 | pt = vgpu->gtt.ggtt_mm->ggtt_mm.virtual_ggtt + offset; |
87 | if (read) |
88 | memcpy(p_data, pt, bytes); |
89 | else |
90 | memcpy(pt, p_data, bytes); |
91 | |
92 | } |
93 | mutex_unlock(lock: &vgpu->vgpu_lock); |
94 | } |
95 | |
96 | /** |
97 | * intel_vgpu_emulate_mmio_read - emulate MMIO read |
98 | * @vgpu: a vGPU |
99 | * @pa: guest physical address |
100 | * @p_data: data return buffer |
101 | * @bytes: access data length |
102 | * |
103 | * Returns: |
104 | * Zero on success, negative error code if failed |
105 | */ |
106 | int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa, |
107 | void *p_data, unsigned int bytes) |
108 | { |
109 | struct intel_gvt *gvt = vgpu->gvt; |
110 | struct drm_i915_private *i915 = gvt->gt->i915; |
111 | unsigned int offset = 0; |
112 | int ret = -EINVAL; |
113 | |
114 | if (vgpu->failsafe) { |
115 | failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, read: true); |
116 | return 0; |
117 | } |
118 | mutex_lock(&vgpu->vgpu_lock); |
119 | |
120 | offset = intel_vgpu_gpa_to_mmio_offset(vgpu, gpa: pa); |
121 | |
122 | if (drm_WARN_ON(&i915->drm, bytes > 8)) |
123 | goto err; |
124 | |
125 | if (reg_is_gtt(gvt, offset)) { |
126 | if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4) && |
127 | !IS_ALIGNED(offset, 8))) |
128 | goto err; |
129 | if (drm_WARN_ON(&i915->drm, bytes != 4 && bytes != 8)) |
130 | goto err; |
131 | if (drm_WARN_ON(&i915->drm, |
132 | !reg_is_gtt(gvt, offset + bytes - 1))) |
133 | goto err; |
134 | |
135 | ret = intel_vgpu_emulate_ggtt_mmio_read(vgpu, off: offset, |
136 | p_data, bytes); |
137 | if (ret) |
138 | goto err; |
139 | goto out; |
140 | } |
141 | |
142 | if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) { |
143 | ret = intel_gvt_read_gpa(vgpu, gpa: pa, buf: p_data, len: bytes); |
144 | goto out; |
145 | } |
146 | |
147 | if (drm_WARN_ON(&i915->drm, !reg_is_mmio(gvt, offset + bytes - 1))) |
148 | goto err; |
149 | |
150 | if (!intel_gvt_mmio_is_unalign(gvt, offset)) { |
151 | if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, bytes))) |
152 | goto err; |
153 | } |
154 | |
155 | ret = intel_vgpu_mmio_reg_rw(vgpu, offset, pdata: p_data, bytes, is_read: true); |
156 | if (ret < 0) |
157 | goto err; |
158 | |
159 | intel_gvt_mmio_set_accessed(gvt, offset); |
160 | ret = 0; |
161 | goto out; |
162 | |
163 | err: |
164 | gvt_vgpu_err("fail to emulate MMIO read %08x len %d\n" , |
165 | offset, bytes); |
166 | out: |
167 | mutex_unlock(lock: &vgpu->vgpu_lock); |
168 | return ret; |
169 | } |
170 | |
171 | /** |
172 | * intel_vgpu_emulate_mmio_write - emulate MMIO write |
173 | * @vgpu: a vGPU |
174 | * @pa: guest physical address |
175 | * @p_data: write data buffer |
176 | * @bytes: access data length |
177 | * |
178 | * Returns: |
179 | * Zero on success, negative error code if failed |
180 | */ |
181 | int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, u64 pa, |
182 | void *p_data, unsigned int bytes) |
183 | { |
184 | struct intel_gvt *gvt = vgpu->gvt; |
185 | struct drm_i915_private *i915 = gvt->gt->i915; |
186 | unsigned int offset = 0; |
187 | int ret = -EINVAL; |
188 | |
189 | if (vgpu->failsafe) { |
190 | failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, read: false); |
191 | return 0; |
192 | } |
193 | |
194 | mutex_lock(&vgpu->vgpu_lock); |
195 | |
196 | offset = intel_vgpu_gpa_to_mmio_offset(vgpu, gpa: pa); |
197 | |
198 | if (drm_WARN_ON(&i915->drm, bytes > 8)) |
199 | goto err; |
200 | |
201 | if (reg_is_gtt(gvt, offset)) { |
202 | if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4) && |
203 | !IS_ALIGNED(offset, 8))) |
204 | goto err; |
205 | if (drm_WARN_ON(&i915->drm, bytes != 4 && bytes != 8)) |
206 | goto err; |
207 | if (drm_WARN_ON(&i915->drm, |
208 | !reg_is_gtt(gvt, offset + bytes - 1))) |
209 | goto err; |
210 | |
211 | ret = intel_vgpu_emulate_ggtt_mmio_write(vgpu, off: offset, |
212 | p_data, bytes); |
213 | if (ret) |
214 | goto err; |
215 | goto out; |
216 | } |
217 | |
218 | if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) { |
219 | ret = intel_gvt_write_gpa(vgpu, gpa: pa, buf: p_data, len: bytes); |
220 | goto out; |
221 | } |
222 | |
223 | ret = intel_vgpu_mmio_reg_rw(vgpu, offset, pdata: p_data, bytes, is_read: false); |
224 | if (ret < 0) |
225 | goto err; |
226 | |
227 | intel_gvt_mmio_set_accessed(gvt, offset); |
228 | ret = 0; |
229 | goto out; |
230 | err: |
231 | gvt_vgpu_err("fail to emulate MMIO write %08x len %d\n" , offset, |
232 | bytes); |
233 | out: |
234 | mutex_unlock(lock: &vgpu->vgpu_lock); |
235 | return ret; |
236 | } |
237 | |
238 | |
239 | /** |
240 | * intel_vgpu_reset_mmio - reset virtual MMIO space |
241 | * @vgpu: a vGPU |
242 | * @dmlr: whether this is device model level reset |
243 | */ |
244 | void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr) |
245 | { |
246 | struct intel_gvt *gvt = vgpu->gvt; |
247 | const struct intel_gvt_device_info *info = &gvt->device_info; |
248 | void *mmio = gvt->firmware.mmio; |
249 | |
250 | if (dmlr) { |
251 | memcpy(vgpu->mmio.vreg, mmio, info->mmio_size); |
252 | |
253 | vgpu_vreg_t(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0; |
254 | |
255 | /* set the bit 0:2(Core C-State ) to C0 */ |
256 | vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0; |
257 | |
258 | /* uc reset hw expect GS_MIA_IN_RESET */ |
259 | vgpu_vreg_t(vgpu, GUC_STATUS) |= GS_MIA_IN_RESET; |
260 | |
261 | if (IS_BROXTON(vgpu->gvt->gt->i915)) { |
262 | vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= |
263 | ~(BIT(0) | BIT(1)); |
264 | vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &= |
265 | ~PHY_POWER_GOOD; |
266 | vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &= |
267 | ~PHY_POWER_GOOD; |
268 | vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &= |
269 | ~BIT(30); |
270 | vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &= |
271 | ~BIT(30); |
272 | vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &= |
273 | ~BXT_PHY_LANE_ENABLED; |
274 | vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |= |
275 | BXT_PHY_CMNLANE_POWERDOWN_ACK | |
276 | BXT_PHY_LANE_POWERDOWN_ACK; |
277 | vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &= |
278 | ~BXT_PHY_LANE_ENABLED; |
279 | vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |= |
280 | BXT_PHY_CMNLANE_POWERDOWN_ACK | |
281 | BXT_PHY_LANE_POWERDOWN_ACK; |
282 | vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &= |
283 | ~BXT_PHY_LANE_ENABLED; |
284 | vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |= |
285 | BXT_PHY_CMNLANE_POWERDOWN_ACK | |
286 | BXT_PHY_LANE_POWERDOWN_ACK; |
287 | vgpu_vreg_t(vgpu, SKL_FUSE_STATUS) |= |
288 | SKL_FUSE_DOWNLOAD_STATUS | |
289 | SKL_FUSE_PG_DIST_STATUS(SKL_PG0) | |
290 | SKL_FUSE_PG_DIST_STATUS(SKL_PG1) | |
291 | SKL_FUSE_PG_DIST_STATUS(SKL_PG2); |
292 | } |
293 | } else { |
294 | #define GVT_GEN8_MMIO_RESET_OFFSET (0x44200) |
295 | /* only reset the engine related, so starting with 0x44200 |
296 | * interrupt include DE,display mmio related will not be |
297 | * touched |
298 | */ |
299 | memcpy(vgpu->mmio.vreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); |
300 | } |
301 | |
302 | } |
303 | |
304 | /** |
305 | * intel_vgpu_init_mmio - init MMIO space |
306 | * @vgpu: a vGPU |
307 | * |
308 | * Returns: |
309 | * Zero on success, negative error code if failed |
310 | */ |
311 | int intel_vgpu_init_mmio(struct intel_vgpu *vgpu) |
312 | { |
313 | const struct intel_gvt_device_info *info = &vgpu->gvt->device_info; |
314 | |
315 | vgpu->mmio.vreg = vzalloc(size: info->mmio_size); |
316 | if (!vgpu->mmio.vreg) |
317 | return -ENOMEM; |
318 | |
319 | intel_vgpu_reset_mmio(vgpu, dmlr: true); |
320 | |
321 | return 0; |
322 | } |
323 | |
324 | /** |
325 | * intel_vgpu_clean_mmio - clean MMIO space |
326 | * @vgpu: a vGPU |
327 | * |
328 | */ |
329 | void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu) |
330 | { |
331 | vfree(addr: vgpu->mmio.vreg); |
332 | vgpu->mmio.vreg = NULL; |
333 | } |
334 | |