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 "gvt.h" 38 39 /** 40 * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset 41 * @vgpu: a vGPU 42 * 43 * Returns: 44 * Zero on success, negative error code if failed 45 */ 46 int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) 47 { 48 u64 gttmmio_gpa = intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0); 49 return gpa - gttmmio_gpa; 50 } 51 52 #define reg_is_mmio(gvt, reg) \ 53 (reg >= 0 && reg < gvt->device_info.mmio_size) 54 55 #define reg_is_gtt(gvt, reg) \ 56 (reg >= gvt->device_info.gtt_start_offset \ 57 && reg < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) 58 59 static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, uint64_t pa, 60 void *p_data, unsigned int bytes, bool read) 61 { 62 struct intel_gvt *gvt = NULL; 63 void *pt = NULL; 64 unsigned int offset = 0; 65 66 if (!vgpu || !p_data) 67 return; 68 69 gvt = vgpu->gvt; 70 mutex_lock(&gvt->lock); 71 offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); 72 if (reg_is_mmio(gvt, offset)) { 73 if (read) 74 intel_vgpu_default_mmio_read(vgpu, offset, p_data, 75 bytes); 76 else 77 intel_vgpu_default_mmio_write(vgpu, offset, p_data, 78 bytes); 79 } else if (reg_is_gtt(gvt, offset) && 80 vgpu->gtt.ggtt_mm->virtual_page_table) { 81 offset -= gvt->device_info.gtt_start_offset; 82 pt = vgpu->gtt.ggtt_mm->virtual_page_table + offset; 83 if (read) 84 memcpy(p_data, pt, bytes); 85 else 86 memcpy(pt, p_data, bytes); 87 88 } 89 mutex_unlock(&gvt->lock); 90 } 91 92 /** 93 * intel_vgpu_emulate_mmio_read - emulate MMIO read 94 * @vgpu: a vGPU 95 * @pa: guest physical address 96 * @p_data: data return buffer 97 * @bytes: access data length 98 * 99 * Returns: 100 * Zero on success, negative error code if failed 101 */ 102 int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa, 103 void *p_data, unsigned int bytes) 104 { 105 struct intel_gvt *gvt = vgpu->gvt; 106 unsigned int offset = 0; 107 int ret = -EINVAL; 108 109 if (vgpu->failsafe) { 110 failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, true); 111 return 0; 112 } 113 mutex_lock(&gvt->lock); 114 115 offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); 116 117 if (WARN_ON(bytes > 8)) 118 goto err; 119 120 if (reg_is_gtt(gvt, offset)) { 121 if (WARN_ON(!IS_ALIGNED(offset, 4) && !IS_ALIGNED(offset, 8))) 122 goto err; 123 if (WARN_ON(bytes != 4 && bytes != 8)) 124 goto err; 125 if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1))) 126 goto err; 127 128 ret = intel_vgpu_emulate_gtt_mmio_read(vgpu, offset, 129 p_data, bytes); 130 if (ret) 131 goto err; 132 goto out; 133 } 134 135 if (WARN_ON_ONCE(!reg_is_mmio(gvt, offset))) { 136 ret = intel_gvt_hypervisor_read_gpa(vgpu, pa, p_data, bytes); 137 goto out; 138 } 139 140 if (WARN_ON(!reg_is_mmio(gvt, offset + bytes - 1))) 141 goto err; 142 143 if (!intel_gvt_mmio_is_unalign(gvt, offset)) { 144 if (WARN_ON(!IS_ALIGNED(offset, bytes))) 145 goto err; 146 } 147 148 ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, true); 149 if (ret < 0) 150 goto err; 151 152 intel_gvt_mmio_set_accessed(gvt, offset); 153 ret = 0; 154 goto out; 155 156 err: 157 gvt_vgpu_err("fail to emulate MMIO read %08x len %d\n", 158 offset, bytes); 159 out: 160 mutex_unlock(&gvt->lock); 161 return ret; 162 } 163 164 /** 165 * intel_vgpu_emulate_mmio_write - emulate MMIO write 166 * @vgpu: a vGPU 167 * @pa: guest physical address 168 * @p_data: write data buffer 169 * @bytes: access data length 170 * 171 * Returns: 172 * Zero on success, negative error code if failed 173 */ 174 int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa, 175 void *p_data, unsigned int bytes) 176 { 177 struct intel_gvt *gvt = vgpu->gvt; 178 unsigned int offset = 0; 179 int ret = -EINVAL; 180 181 if (vgpu->failsafe) { 182 failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, false); 183 return 0; 184 } 185 186 mutex_lock(&gvt->lock); 187 188 offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); 189 190 if (WARN_ON(bytes > 8)) 191 goto err; 192 193 if (reg_is_gtt(gvt, offset)) { 194 if (WARN_ON(!IS_ALIGNED(offset, 4) && !IS_ALIGNED(offset, 8))) 195 goto err; 196 if (WARN_ON(bytes != 4 && bytes != 8)) 197 goto err; 198 if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1))) 199 goto err; 200 201 ret = intel_vgpu_emulate_gtt_mmio_write(vgpu, offset, 202 p_data, bytes); 203 if (ret) 204 goto err; 205 goto out; 206 } 207 208 if (WARN_ON_ONCE(!reg_is_mmio(gvt, offset))) { 209 ret = intel_gvt_hypervisor_write_gpa(vgpu, pa, p_data, bytes); 210 goto out; 211 } 212 213 ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, false); 214 if (ret < 0) 215 goto err; 216 217 intel_gvt_mmio_set_accessed(gvt, offset); 218 ret = 0; 219 goto out; 220 err: 221 gvt_vgpu_err("fail to emulate MMIO write %08x len %d\n", offset, 222 bytes); 223 out: 224 mutex_unlock(&gvt->lock); 225 return ret; 226 } 227 228 229 /** 230 * intel_vgpu_reset_mmio - reset virtual MMIO space 231 * @vgpu: a vGPU 232 * 233 */ 234 void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr) 235 { 236 struct intel_gvt *gvt = vgpu->gvt; 237 const struct intel_gvt_device_info *info = &gvt->device_info; 238 void *mmio = gvt->firmware.mmio; 239 240 if (dmlr) { 241 memcpy(vgpu->mmio.vreg, mmio, info->mmio_size); 242 memcpy(vgpu->mmio.sreg, mmio, info->mmio_size); 243 244 vgpu_vreg_t(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0; 245 246 /* set the bit 0:2(Core C-State ) to C0 */ 247 vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0; 248 249 vgpu->mmio.disable_warn_untrack = false; 250 } else { 251 #define GVT_GEN8_MMIO_RESET_OFFSET (0x44200) 252 /* only reset the engine related, so starting with 0x44200 253 * interrupt include DE,display mmio related will not be 254 * touched 255 */ 256 memcpy(vgpu->mmio.vreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); 257 memcpy(vgpu->mmio.sreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); 258 } 259 260 } 261 262 /** 263 * intel_vgpu_init_mmio - init MMIO space 264 * @vgpu: a vGPU 265 * 266 * Returns: 267 * Zero on success, negative error code if failed 268 */ 269 int intel_vgpu_init_mmio(struct intel_vgpu *vgpu) 270 { 271 const struct intel_gvt_device_info *info = &vgpu->gvt->device_info; 272 273 vgpu->mmio.vreg = vzalloc(info->mmio_size * 2); 274 if (!vgpu->mmio.vreg) 275 return -ENOMEM; 276 277 vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size; 278 279 intel_vgpu_reset_mmio(vgpu, true); 280 281 return 0; 282 } 283 284 /** 285 * intel_vgpu_clean_mmio - clean MMIO space 286 * @vgpu: a vGPU 287 * 288 */ 289 void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu) 290 { 291 vfree(vgpu->mmio.vreg); 292 vgpu->mmio.vreg = vgpu->mmio.sreg = NULL; 293 } 294