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