]>
Commit | Line | Data |
---|---|---|
28a60dee 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 | * Kevin Tian <[email protected]> | |
25 | * Dexuan Cui | |
26 | * | |
27 | * Contributors: | |
28 | * Pei Zhang <[email protected]> | |
29 | * Min He <[email protected]> | |
30 | * Niu Bing <[email protected]> | |
31 | * Yulei Zhang <[email protected]> | |
32 | * Zhenyu Wang <[email protected]> | |
33 | * Zhi Wang <[email protected]> | |
34 | * | |
35 | */ | |
36 | ||
37 | #include "i915_drv.h" | |
feddf6e8 | 38 | #include "gvt.h" |
28a60dee | 39 | |
28a60dee ZW |
40 | static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm) |
41 | { | |
42 | struct intel_gvt *gvt = vgpu->gvt; | |
43 | struct drm_i915_private *dev_priv = gvt->dev_priv; | |
e007b19d | 44 | unsigned int flags; |
28a60dee ZW |
45 | u64 start, end, size; |
46 | struct drm_mm_node *node; | |
28a60dee ZW |
47 | int ret; |
48 | ||
49 | if (high_gm) { | |
28a60dee ZW |
50 | node = &vgpu->gm.high_gm_node; |
51 | size = vgpu_hidden_sz(vgpu); | |
5b3cac19 ZW |
52 | start = ALIGN(gvt_hidden_gmadr_base(gvt), I915_GTT_PAGE_SIZE); |
53 | end = ALIGN(gvt_hidden_gmadr_end(gvt), I915_GTT_PAGE_SIZE); | |
e007b19d | 54 | flags = PIN_HIGH; |
28a60dee | 55 | } else { |
28a60dee ZW |
56 | node = &vgpu->gm.low_gm_node; |
57 | size = vgpu_aperture_sz(vgpu); | |
5b3cac19 ZW |
58 | start = ALIGN(gvt_aperture_gmadr_base(gvt), I915_GTT_PAGE_SIZE); |
59 | end = ALIGN(gvt_aperture_gmadr_end(gvt), I915_GTT_PAGE_SIZE); | |
e007b19d | 60 | flags = PIN_MAPPABLE; |
28a60dee ZW |
61 | } |
62 | ||
63 | mutex_lock(&dev_priv->drm.struct_mutex); | |
f3be657d | 64 | mmio_hw_access_pre(dev_priv); |
82ad6443 | 65 | ret = i915_gem_gtt_insert(&dev_priv->ggtt.vm, node, |
5b3cac19 ZW |
66 | size, I915_GTT_PAGE_SIZE, |
67 | I915_COLOR_UNEVICTABLE, | |
e007b19d | 68 | start, end, flags); |
f3be657d | 69 | mmio_hw_access_post(dev_priv); |
28a60dee | 70 | mutex_unlock(&dev_priv->drm.struct_mutex); |
e007b19d CW |
71 | if (ret) |
72 | gvt_err("fail to alloc %s gm space from host\n", | |
73 | high_gm ? "high" : "low"); | |
74 | ||
28a60dee ZW |
75 | return ret; |
76 | } | |
77 | ||
78 | static int alloc_vgpu_gm(struct intel_vgpu *vgpu) | |
79 | { | |
80 | struct intel_gvt *gvt = vgpu->gvt; | |
81 | struct drm_i915_private *dev_priv = gvt->dev_priv; | |
82 | int ret; | |
83 | ||
84 | ret = alloc_gm(vgpu, false); | |
85 | if (ret) | |
86 | return ret; | |
87 | ||
88 | ret = alloc_gm(vgpu, true); | |
89 | if (ret) | |
90 | goto out_free_aperture; | |
91 | ||
92 | gvt_dbg_core("vgpu%d: alloc low GM start %llx size %llx\n", vgpu->id, | |
93 | vgpu_aperture_offset(vgpu), vgpu_aperture_sz(vgpu)); | |
94 | ||
95 | gvt_dbg_core("vgpu%d: alloc high GM start %llx size %llx\n", vgpu->id, | |
96 | vgpu_hidden_offset(vgpu), vgpu_hidden_sz(vgpu)); | |
97 | ||
98 | return 0; | |
99 | out_free_aperture: | |
100 | mutex_lock(&dev_priv->drm.struct_mutex); | |
101 | drm_mm_remove_node(&vgpu->gm.low_gm_node); | |
102 | mutex_unlock(&dev_priv->drm.struct_mutex); | |
103 | return ret; | |
104 | } | |
105 | ||
106 | static void free_vgpu_gm(struct intel_vgpu *vgpu) | |
107 | { | |
108 | struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; | |
109 | ||
110 | mutex_lock(&dev_priv->drm.struct_mutex); | |
111 | drm_mm_remove_node(&vgpu->gm.low_gm_node); | |
112 | drm_mm_remove_node(&vgpu->gm.high_gm_node); | |
113 | mutex_unlock(&dev_priv->drm.struct_mutex); | |
114 | } | |
115 | ||
116 | /** | |
117 | * intel_vgpu_write_fence - write fence registers owned by a vGPU | |
118 | * @vgpu: vGPU instance | |
119 | * @fence: vGPU fence register number | |
120 | * @value: Fence register value to be written | |
121 | * | |
122 | * This function is used to write fence registers owned by a vGPU. The vGPU | |
123 | * fence register number will be translated into HW fence register number. | |
124 | * | |
125 | */ | |
126 | void intel_vgpu_write_fence(struct intel_vgpu *vgpu, | |
127 | u32 fence, u64 value) | |
128 | { | |
129 | struct intel_gvt *gvt = vgpu->gvt; | |
130 | struct drm_i915_private *dev_priv = gvt->dev_priv; | |
131 | struct drm_i915_fence_reg *reg; | |
132 | i915_reg_t fence_reg_lo, fence_reg_hi; | |
133 | ||
75ea10da CW |
134 | assert_rpm_wakelock_held(dev_priv); |
135 | ||
4b25e737 | 136 | if (WARN_ON(fence >= vgpu_fence_sz(vgpu))) |
28a60dee ZW |
137 | return; |
138 | ||
139 | reg = vgpu->fence.regs[fence]; | |
140 | if (WARN_ON(!reg)) | |
141 | return; | |
142 | ||
143 | fence_reg_lo = FENCE_REG_GEN6_LO(reg->id); | |
144 | fence_reg_hi = FENCE_REG_GEN6_HI(reg->id); | |
145 | ||
146 | I915_WRITE(fence_reg_lo, 0); | |
147 | POSTING_READ(fence_reg_lo); | |
148 | ||
149 | I915_WRITE(fence_reg_hi, upper_32_bits(value)); | |
150 | I915_WRITE(fence_reg_lo, lower_32_bits(value)); | |
151 | POSTING_READ(fence_reg_lo); | |
152 | } | |
153 | ||
d22a48bf CD |
154 | static void _clear_vgpu_fence(struct intel_vgpu *vgpu) |
155 | { | |
156 | int i; | |
157 | ||
158 | for (i = 0; i < vgpu_fence_sz(vgpu); i++) | |
159 | intel_vgpu_write_fence(vgpu, i, 0); | |
160 | } | |
161 | ||
28a60dee ZW |
162 | static void free_vgpu_fence(struct intel_vgpu *vgpu) |
163 | { | |
164 | struct intel_gvt *gvt = vgpu->gvt; | |
165 | struct drm_i915_private *dev_priv = gvt->dev_priv; | |
166 | struct drm_i915_fence_reg *reg; | |
167 | u32 i; | |
168 | ||
169 | if (WARN_ON(!vgpu_fence_sz(vgpu))) | |
170 | return; | |
171 | ||
75ea10da CW |
172 | intel_runtime_pm_get(dev_priv); |
173 | ||
28a60dee | 174 | mutex_lock(&dev_priv->drm.struct_mutex); |
d22a48bf | 175 | _clear_vgpu_fence(vgpu); |
28a60dee ZW |
176 | for (i = 0; i < vgpu_fence_sz(vgpu); i++) { |
177 | reg = vgpu->fence.regs[i]; | |
969b0950 CD |
178 | i915_unreserve_fence(reg); |
179 | vgpu->fence.regs[i] = NULL; | |
28a60dee ZW |
180 | } |
181 | mutex_unlock(&dev_priv->drm.struct_mutex); | |
75ea10da CW |
182 | |
183 | intel_runtime_pm_put(dev_priv); | |
28a60dee ZW |
184 | } |
185 | ||
186 | static int alloc_vgpu_fence(struct intel_vgpu *vgpu) | |
187 | { | |
188 | struct intel_gvt *gvt = vgpu->gvt; | |
189 | struct drm_i915_private *dev_priv = gvt->dev_priv; | |
190 | struct drm_i915_fence_reg *reg; | |
191 | int i; | |
28a60dee | 192 | |
75ea10da CW |
193 | intel_runtime_pm_get(dev_priv); |
194 | ||
28a60dee ZW |
195 | /* Request fences from host */ |
196 | mutex_lock(&dev_priv->drm.struct_mutex); | |
969b0950 CD |
197 | |
198 | for (i = 0; i < vgpu_fence_sz(vgpu); i++) { | |
199 | reg = i915_reserve_fence(dev_priv); | |
200 | if (IS_ERR(reg)) | |
201 | goto out_free_fence; | |
202 | ||
28a60dee | 203 | vgpu->fence.regs[i] = reg; |
28a60dee | 204 | } |
28a60dee | 205 | |
d22a48bf CD |
206 | _clear_vgpu_fence(vgpu); |
207 | ||
28a60dee | 208 | mutex_unlock(&dev_priv->drm.struct_mutex); |
75ea10da | 209 | intel_runtime_pm_put(dev_priv); |
28a60dee ZW |
210 | return 0; |
211 | out_free_fence: | |
969b0950 | 212 | gvt_vgpu_err("Failed to alloc fences\n"); |
28a60dee ZW |
213 | /* Return fences to host, if fail */ |
214 | for (i = 0; i < vgpu_fence_sz(vgpu); i++) { | |
215 | reg = vgpu->fence.regs[i]; | |
216 | if (!reg) | |
217 | continue; | |
969b0950 CD |
218 | i915_unreserve_fence(reg); |
219 | vgpu->fence.regs[i] = NULL; | |
28a60dee ZW |
220 | } |
221 | mutex_unlock(&dev_priv->drm.struct_mutex); | |
75ea10da | 222 | intel_runtime_pm_put(dev_priv); |
28a60dee ZW |
223 | return -ENOSPC; |
224 | } | |
225 | ||
226 | static void free_resource(struct intel_vgpu *vgpu) | |
227 | { | |
228 | struct intel_gvt *gvt = vgpu->gvt; | |
229 | ||
230 | gvt->gm.vgpu_allocated_low_gm_size -= vgpu_aperture_sz(vgpu); | |
231 | gvt->gm.vgpu_allocated_high_gm_size -= vgpu_hidden_sz(vgpu); | |
232 | gvt->fence.vgpu_allocated_fence_num -= vgpu_fence_sz(vgpu); | |
233 | } | |
234 | ||
235 | static int alloc_resource(struct intel_vgpu *vgpu, | |
236 | struct intel_vgpu_creation_params *param) | |
237 | { | |
238 | struct intel_gvt *gvt = vgpu->gvt; | |
239 | unsigned long request, avail, max, taken; | |
240 | const char *item; | |
241 | ||
242 | if (!param->low_gm_sz || !param->high_gm_sz || !param->fence_sz) { | |
695fbc08 | 243 | gvt_vgpu_err("Invalid vGPU creation params\n"); |
28a60dee ZW |
244 | return -EINVAL; |
245 | } | |
246 | ||
247 | item = "low GM space"; | |
248 | max = gvt_aperture_sz(gvt) - HOST_LOW_GM_SIZE; | |
249 | taken = gvt->gm.vgpu_allocated_low_gm_size; | |
250 | avail = max - taken; | |
251 | request = MB_TO_BYTES(param->low_gm_sz); | |
252 | ||
253 | if (request > avail) | |
254 | goto no_enough_resource; | |
255 | ||
5b3cac19 | 256 | vgpu_aperture_sz(vgpu) = ALIGN(request, I915_GTT_PAGE_SIZE); |
28a60dee ZW |
257 | |
258 | item = "high GM space"; | |
259 | max = gvt_hidden_sz(gvt) - HOST_HIGH_GM_SIZE; | |
260 | taken = gvt->gm.vgpu_allocated_high_gm_size; | |
261 | avail = max - taken; | |
262 | request = MB_TO_BYTES(param->high_gm_sz); | |
263 | ||
264 | if (request > avail) | |
265 | goto no_enough_resource; | |
266 | ||
5b3cac19 | 267 | vgpu_hidden_sz(vgpu) = ALIGN(request, I915_GTT_PAGE_SIZE); |
28a60dee ZW |
268 | |
269 | item = "fence"; | |
270 | max = gvt_fence_sz(gvt) - HOST_FENCE; | |
271 | taken = gvt->fence.vgpu_allocated_fence_num; | |
272 | avail = max - taken; | |
273 | request = param->fence_sz; | |
274 | ||
275 | if (request > avail) | |
276 | goto no_enough_resource; | |
277 | ||
278 | vgpu_fence_sz(vgpu) = request; | |
279 | ||
280 | gvt->gm.vgpu_allocated_low_gm_size += MB_TO_BYTES(param->low_gm_sz); | |
281 | gvt->gm.vgpu_allocated_high_gm_size += MB_TO_BYTES(param->high_gm_sz); | |
282 | gvt->fence.vgpu_allocated_fence_num += param->fence_sz; | |
283 | return 0; | |
284 | ||
285 | no_enough_resource: | |
4cf196eb CD |
286 | gvt_err("fail to allocate resource %s\n", item); |
287 | gvt_err("request %luMB avail %luMB max %luMB taken %luMB\n", | |
695fbc08 | 288 | BYTES_TO_MB(request), BYTES_TO_MB(avail), |
28a60dee ZW |
289 | BYTES_TO_MB(max), BYTES_TO_MB(taken)); |
290 | return -ENOSPC; | |
291 | } | |
292 | ||
293 | /** | |
294 | * inte_gvt_free_vgpu_resource - free HW resource owned by a vGPU | |
295 | * @vgpu: a vGPU | |
296 | * | |
297 | * This function is used to free the HW resource owned by a vGPU. | |
298 | * | |
299 | */ | |
300 | void intel_vgpu_free_resource(struct intel_vgpu *vgpu) | |
301 | { | |
302 | free_vgpu_gm(vgpu); | |
303 | free_vgpu_fence(vgpu); | |
304 | free_resource(vgpu); | |
305 | } | |
306 | ||
d22a48bf CD |
307 | /** |
308 | * intel_vgpu_reset_resource - reset resource state owned by a vGPU | |
309 | * @vgpu: a vGPU | |
310 | * | |
311 | * This function is used to reset resource state owned by a vGPU. | |
312 | * | |
313 | */ | |
314 | void intel_vgpu_reset_resource(struct intel_vgpu *vgpu) | |
315 | { | |
316 | struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; | |
317 | ||
318 | intel_runtime_pm_get(dev_priv); | |
319 | _clear_vgpu_fence(vgpu); | |
320 | intel_runtime_pm_put(dev_priv); | |
321 | } | |
322 | ||
28a60dee ZW |
323 | /** |
324 | * intel_alloc_vgpu_resource - allocate HW resource for a vGPU | |
325 | * @vgpu: vGPU | |
326 | * @param: vGPU creation params | |
327 | * | |
328 | * This function is used to allocate HW resource for a vGPU. User specifies | |
329 | * the resource configuration through the creation params. | |
330 | * | |
331 | * Returns: | |
332 | * zero on success, negative error code if failed. | |
333 | * | |
334 | */ | |
335 | int intel_vgpu_alloc_resource(struct intel_vgpu *vgpu, | |
336 | struct intel_vgpu_creation_params *param) | |
337 | { | |
338 | int ret; | |
339 | ||
340 | ret = alloc_resource(vgpu, param); | |
341 | if (ret) | |
342 | return ret; | |
343 | ||
344 | ret = alloc_vgpu_gm(vgpu); | |
345 | if (ret) | |
346 | goto out_free_resource; | |
347 | ||
348 | ret = alloc_vgpu_fence(vgpu); | |
349 | if (ret) | |
350 | goto out_free_vgpu_gm; | |
351 | ||
352 | return 0; | |
353 | ||
354 | out_free_vgpu_gm: | |
355 | free_vgpu_gm(vgpu); | |
356 | out_free_resource: | |
357 | free_resource(vgpu); | |
358 | return ret; | |
359 | } |