1/* $NetBSD: aperture_gm.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $ */ 2 3/* 4 * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Kevin Tian <kevin.tian@intel.com> 27 * Dexuan Cui 28 * 29 * Contributors: 30 * Pei Zhang <pei.zhang@intel.com> 31 * Min He <min.he@intel.com> 32 * Niu Bing <bing.niu@intel.com> 33 * Yulei Zhang <yulei.zhang@intel.com> 34 * Zhenyu Wang <zhenyuw@linux.intel.com> 35 * Zhi Wang <zhi.a.wang@intel.com> 36 * 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: aperture_gm.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $"); 41 42#include "i915_drv.h" 43#include "i915_gem_fence_reg.h" 44#include "gvt.h" 45 46static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm) 47{ 48 struct intel_gvt *gvt = vgpu->gvt; 49 struct drm_i915_private *dev_priv = gvt->dev_priv; 50 unsigned int flags; 51 u64 start, end, size; 52 struct drm_mm_node *node; 53 int ret; 54 55 if (high_gm) { 56 node = &vgpu->gm.high_gm_node; 57 size = vgpu_hidden_sz(vgpu); 58 start = ALIGN(gvt_hidden_gmadr_base(gvt), I915_GTT_PAGE_SIZE); 59 end = ALIGN(gvt_hidden_gmadr_end(gvt), I915_GTT_PAGE_SIZE); 60 flags = PIN_HIGH; 61 } else { 62 node = &vgpu->gm.low_gm_node; 63 size = vgpu_aperture_sz(vgpu); 64 start = ALIGN(gvt_aperture_gmadr_base(gvt), I915_GTT_PAGE_SIZE); 65 end = ALIGN(gvt_aperture_gmadr_end(gvt), I915_GTT_PAGE_SIZE); 66 flags = PIN_MAPPABLE; 67 } 68 69 mutex_lock(&dev_priv->ggtt.vm.mutex); 70 mmio_hw_access_pre(dev_priv); 71 ret = i915_gem_gtt_insert(&dev_priv->ggtt.vm, node, 72 size, I915_GTT_PAGE_SIZE, 73 I915_COLOR_UNEVICTABLE, 74 start, end, flags); 75 mmio_hw_access_post(dev_priv); 76 mutex_unlock(&dev_priv->ggtt.vm.mutex); 77 if (ret) 78 gvt_err("fail to alloc %s gm space from host\n", 79 high_gm ? "high" : "low"); 80 81 return ret; 82} 83 84static int alloc_vgpu_gm(struct intel_vgpu *vgpu) 85{ 86 struct intel_gvt *gvt = vgpu->gvt; 87 struct drm_i915_private *dev_priv = gvt->dev_priv; 88 int ret; 89 90 ret = alloc_gm(vgpu, false); 91 if (ret) 92 return ret; 93 94 ret = alloc_gm(vgpu, true); 95 if (ret) 96 goto out_free_aperture; 97 98 gvt_dbg_core("vgpu%d: alloc low GM start %llx size %llx\n", vgpu->id, 99 vgpu_aperture_offset(vgpu), vgpu_aperture_sz(vgpu)); 100 101 gvt_dbg_core("vgpu%d: alloc high GM start %llx size %llx\n", vgpu->id, 102 vgpu_hidden_offset(vgpu), vgpu_hidden_sz(vgpu)); 103 104 return 0; 105out_free_aperture: 106 mutex_lock(&dev_priv->ggtt.vm.mutex); 107 drm_mm_remove_node(&vgpu->gm.low_gm_node); 108 mutex_unlock(&dev_priv->ggtt.vm.mutex); 109 return ret; 110} 111 112static void free_vgpu_gm(struct intel_vgpu *vgpu) 113{ 114 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; 115 116 mutex_lock(&dev_priv->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(&dev_priv->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 */ 132void 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 *dev_priv = gvt->dev_priv; 137 struct i915_fence_reg *reg; 138 i915_reg_t fence_reg_lo, fence_reg_hi; 139 140 assert_rpm_wakelock_held(&dev_priv->runtime_pm); 141 142 if (WARN_ON(fence >= vgpu_fence_sz(vgpu))) 143 return; 144 145 reg = vgpu->fence.regs[fence]; 146 if (WARN_ON(!reg)) 147 return; 148 149 fence_reg_lo = FENCE_REG_GEN6_LO(reg->id); 150 fence_reg_hi = FENCE_REG_GEN6_HI(reg->id); 151 152 I915_WRITE(fence_reg_lo, 0); 153 POSTING_READ(fence_reg_lo); 154 155 I915_WRITE(fence_reg_hi, upper_32_bits(value)); 156 I915_WRITE(fence_reg_lo, lower_32_bits(value)); 157 POSTING_READ(fence_reg_lo); 158} 159 160static void _clear_vgpu_fence(struct intel_vgpu *vgpu) 161{ 162 int i; 163 164 for (i = 0; i < vgpu_fence_sz(vgpu); i++) 165 intel_vgpu_write_fence(vgpu, i, 0); 166} 167 168static void free_vgpu_fence(struct intel_vgpu *vgpu) 169{ 170 struct intel_gvt *gvt = vgpu->gvt; 171 struct drm_i915_private *dev_priv = gvt->dev_priv; 172 struct i915_fence_reg *reg; 173 u32 i; 174 175 if (WARN_ON(!vgpu_fence_sz(vgpu))) 176 return; 177 178 intel_runtime_pm_get(&dev_priv->runtime_pm); 179 180 mutex_lock(&dev_priv->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(&dev_priv->ggtt.vm.mutex); 188 189 intel_runtime_pm_put_unchecked(&dev_priv->runtime_pm); 190} 191 192static int alloc_vgpu_fence(struct intel_vgpu *vgpu) 193{ 194 struct intel_gvt *gvt = vgpu->gvt; 195 struct drm_i915_private *dev_priv = gvt->dev_priv; 196 struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; 197 struct i915_fence_reg *reg; 198 int i; 199 200 intel_runtime_pm_get(rpm); 201 202 /* Request fences from host */ 203 mutex_lock(&dev_priv->ggtt.vm.mutex); 204 205 for (i = 0; i < vgpu_fence_sz(vgpu); i++) { 206 reg = i915_reserve_fence(&dev_priv->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(&dev_priv->ggtt.vm.mutex); 216 intel_runtime_pm_put_unchecked(rpm); 217 return 0; 218out_free_fence: 219 gvt_vgpu_err("Failed to alloc fences\n"); 220 /* Return fences to host, if fail */ 221 for (i = 0; i < vgpu_fence_sz(vgpu); i++) { 222 reg = vgpu->fence.regs[i]; 223 if (!reg) 224 continue; 225 i915_unreserve_fence(reg); 226 vgpu->fence.regs[i] = NULL; 227 } 228 mutex_unlock(&dev_priv->ggtt.vm.mutex); 229 intel_runtime_pm_put_unchecked(rpm); 230 return -ENOSPC; 231} 232 233static void free_resource(struct intel_vgpu *vgpu) 234{ 235 struct intel_gvt *gvt = vgpu->gvt; 236 237 gvt->gm.vgpu_allocated_low_gm_size -= vgpu_aperture_sz(vgpu); 238 gvt->gm.vgpu_allocated_high_gm_size -= vgpu_hidden_sz(vgpu); 239 gvt->fence.vgpu_allocated_fence_num -= vgpu_fence_sz(vgpu); 240} 241 242static int alloc_resource(struct intel_vgpu *vgpu, 243 struct intel_vgpu_creation_params *param) 244{ 245 struct intel_gvt *gvt = vgpu->gvt; 246 unsigned long request, avail, max, taken; 247 const char *item; 248 249 if (!param->low_gm_sz || !param->high_gm_sz || !param->fence_sz) { 250 gvt_vgpu_err("Invalid vGPU creation params\n"); 251 return -EINVAL; 252 } 253 254 item = "low GM space"; 255 max = gvt_aperture_sz(gvt) - HOST_LOW_GM_SIZE; 256 taken = gvt->gm.vgpu_allocated_low_gm_size; 257 avail = max - taken; 258 request = MB_TO_BYTES(param->low_gm_sz); 259 260 if (request > avail) 261 goto no_enough_resource; 262 263 vgpu_aperture_sz(vgpu) = ALIGN(request, I915_GTT_PAGE_SIZE); 264 265 item = "high GM space"; 266 max = gvt_hidden_sz(gvt) - HOST_HIGH_GM_SIZE; 267 taken = gvt->gm.vgpu_allocated_high_gm_size; 268 avail = max - taken; 269 request = MB_TO_BYTES(param->high_gm_sz); 270 271 if (request > avail) 272 goto no_enough_resource; 273 274 vgpu_hidden_sz(vgpu) = ALIGN(request, I915_GTT_PAGE_SIZE); 275 276 item = "fence"; 277 max = gvt_fence_sz(gvt) - HOST_FENCE; 278 taken = gvt->fence.vgpu_allocated_fence_num; 279 avail = max - taken; 280 request = param->fence_sz; 281 282 if (request > avail) 283 goto no_enough_resource; 284 285 vgpu_fence_sz(vgpu) = request; 286 287 gvt->gm.vgpu_allocated_low_gm_size += MB_TO_BYTES(param->low_gm_sz); 288 gvt->gm.vgpu_allocated_high_gm_size += MB_TO_BYTES(param->high_gm_sz); 289 gvt->fence.vgpu_allocated_fence_num += param->fence_sz; 290 return 0; 291 292no_enough_resource: 293 gvt_err("fail to allocate resource %s\n", item); 294 gvt_err("request %luMB avail %luMB max %luMB taken %luMB\n", 295 BYTES_TO_MB(request), BYTES_TO_MB(avail), 296 BYTES_TO_MB(max), BYTES_TO_MB(taken)); 297 return -ENOSPC; 298} 299 300/** 301 * inte_gvt_free_vgpu_resource - free HW resource owned by a vGPU 302 * @vgpu: a vGPU 303 * 304 * This function is used to free the HW resource owned by a vGPU. 305 * 306 */ 307void intel_vgpu_free_resource(struct intel_vgpu *vgpu) 308{ 309 free_vgpu_gm(vgpu); 310 free_vgpu_fence(vgpu); 311 free_resource(vgpu); 312} 313 314/** 315 * intel_vgpu_reset_resource - reset resource state owned by a vGPU 316 * @vgpu: a vGPU 317 * 318 * This function is used to reset resource state owned by a vGPU. 319 * 320 */ 321void intel_vgpu_reset_resource(struct intel_vgpu *vgpu) 322{ 323 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; 324 325 intel_runtime_pm_get(&dev_priv->runtime_pm); 326 _clear_vgpu_fence(vgpu); 327 intel_runtime_pm_put_unchecked(&dev_priv->runtime_pm); 328} 329 330/** 331 * intel_alloc_vgpu_resource - allocate HW resource for a vGPU 332 * @vgpu: vGPU 333 * @param: vGPU creation params 334 * 335 * This function is used to allocate HW resource for a vGPU. User specifies 336 * the resource configuration through the creation params. 337 * 338 * Returns: 339 * zero on success, negative error code if failed. 340 * 341 */ 342int intel_vgpu_alloc_resource(struct intel_vgpu *vgpu, 343 struct intel_vgpu_creation_params *param) 344{ 345 int ret; 346 347 ret = alloc_resource(vgpu, param); 348 if (ret) 349 return ret; 350 351 ret = alloc_vgpu_gm(vgpu); 352 if (ret) 353 goto out_free_resource; 354 355 ret = alloc_vgpu_fence(vgpu); 356 if (ret) 357 goto out_free_vgpu_gm; 358 359 return 0; 360 361out_free_vgpu_gm: 362 free_vgpu_gm(vgpu); 363out_free_resource: 364 free_resource(vgpu); 365 return ret; 366} 367