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 * @gpa: guest physical address 43 * 44 * Returns: 45 * Zero on success, negative error code if failed 46 */ 47 int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) 48 { 49 u64 gttmmio_gpa = intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0); 50 return gpa - gttmmio_gpa; 51 } 52 53 #define reg_is_mmio(gvt, reg) \ 54 (reg >= 0 && reg < gvt->device_info.mmio_size) 55 56 #define reg_is_gtt(gvt, reg) \ 57 (reg >= gvt->device_info.gtt_start_offset \ 58 && reg < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) 59 60 static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, uint64_t pa, 61 void *p_data, unsigned int bytes, bool read) 62 { 63 struct intel_gvt *gvt = NULL; 64 void *pt = NULL; 65 unsigned int offset = 0; 66 67 if (!vgpu || !p_data) 68 return; 69 70 gvt = vgpu->gvt; 71 mutex_lock(&vgpu->vgpu_lock); 72 offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); 73 if (reg_is_mmio(gvt, offset)) { 74 if (read) 75 intel_vgpu_default_mmio_read(vgpu, offset, p_data, 76 bytes); 77 else 78 intel_vgpu_default_mmio_write(vgpu, offset, p_data, 79 bytes); 80 } else if (reg_is_gtt(gvt, offset)) { 81 offset -= gvt->device_info.gtt_start_offset; 82 pt = vgpu->gtt.ggtt_mm->ggtt_mm.virtual_ggtt + offset; 83 if (read) 84 memcpy(p_data, pt, bytes); 85 else 86 memcpy(pt, p_data, bytes); 87 88 } 89 mutex_unlock(&vgpu->vgpu_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(&vgpu->vgpu_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_ggtt_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(&vgpu->vgpu_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(&vgpu->vgpu_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_ggtt_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(&vgpu->vgpu_lock); 225 return ret; 226 } 227 228 229 /** 230 * intel_vgpu_reset_mmio - reset virtual MMIO space 231 * @vgpu: a vGPU 232 * @dmlr: whether this is device model level reset 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 if (IS_BROXTON(vgpu->gvt->dev_priv)) { 250 vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= 251 ~(BIT(0) | BIT(1)); 252 vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &= 253 ~PHY_POWER_GOOD; 254 vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &= 255 ~PHY_POWER_GOOD; 256 vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &= 257 ~BIT(30); 258 vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &= 259 ~BIT(30); 260 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &= 261 ~BXT_PHY_LANE_ENABLED; 262 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |= 263 BXT_PHY_CMNLANE_POWERDOWN_ACK | 264 BXT_PHY_LANE_POWERDOWN_ACK; 265 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &= 266 ~BXT_PHY_LANE_ENABLED; 267 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |= 268 BXT_PHY_CMNLANE_POWERDOWN_ACK | 269 BXT_PHY_LANE_POWERDOWN_ACK; 270 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &= 271 ~BXT_PHY_LANE_ENABLED; 272 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |= 273 BXT_PHY_CMNLANE_POWERDOWN_ACK | 274 BXT_PHY_LANE_POWERDOWN_ACK; 275 } 276 } else { 277 #define GVT_GEN8_MMIO_RESET_OFFSET (0x44200) 278 /* only reset the engine related, so starting with 0x44200 279 * interrupt include DE,display mmio related will not be 280 * touched 281 */ 282 memcpy(vgpu->mmio.vreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); 283 memcpy(vgpu->mmio.sreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); 284 } 285 286 } 287 288 /** 289 * intel_vgpu_init_mmio - init MMIO space 290 * @vgpu: a vGPU 291 * 292 * Returns: 293 * Zero on success, negative error code if failed 294 */ 295 int intel_vgpu_init_mmio(struct intel_vgpu *vgpu) 296 { 297 const struct intel_gvt_device_info *info = &vgpu->gvt->device_info; 298 299 vgpu->mmio.vreg = vzalloc(array_size(info->mmio_size, 2)); 300 if (!vgpu->mmio.vreg) 301 return -ENOMEM; 302 303 vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size; 304 305 intel_vgpu_reset_mmio(vgpu, true); 306 307 return 0; 308 } 309 310 /** 311 * intel_vgpu_clean_mmio - clean MMIO space 312 * @vgpu: a vGPU 313 * 314 */ 315 void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu) 316 { 317 vfree(vgpu->mmio.vreg); 318 vgpu->mmio.vreg = vgpu->mmio.sreg = NULL; 319 } 320