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