336 lines · c
1/*2 * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice (including the next12 * paragraph) shall be included in all copies or substantial portions of the13 * Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19 * 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 THE21 * SOFTWARE.22 *23 * Authors:24 * Ke Yu25 * Kevin Tian <kevin.tian@intel.com>26 * Dexuan Cui27 *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 <linux/vmalloc.h>37#include "i915_drv.h"38#include "i915_reg.h"39#include "gvt.h"40 41#include "display/bxt_dpio_phy_regs.h"42#include "display/intel_dpio_phy.h"43#include "gt/intel_gt_regs.h"44 45/**46 * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset47 * @vgpu: a vGPU48 * @gpa: guest physical address49 *50 * Returns:51 * Zero on success, negative error code if failed52 */53int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa)54{55 u64 gttmmio_gpa = intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0);56 return gpa - gttmmio_gpa;57}58 59#define reg_is_mmio(gvt, reg) \60 (reg >= 0 && reg < gvt->device_info.mmio_size)61 62#define reg_is_gtt(gvt, reg) \63 (reg >= gvt->device_info.gtt_start_offset \64 && reg < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt))65 66static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, u64 pa,67 void *p_data, unsigned int bytes, bool read)68{69 struct intel_gvt *gvt = NULL;70 void *pt = NULL;71 unsigned int offset = 0;72 73 if (!vgpu || !p_data)74 return;75 76 gvt = vgpu->gvt;77 mutex_lock(&vgpu->vgpu_lock);78 offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa);79 if (reg_is_mmio(gvt, offset)) {80 if (read)81 intel_vgpu_default_mmio_read(vgpu, offset, p_data,82 bytes);83 else84 intel_vgpu_default_mmio_write(vgpu, offset, p_data,85 bytes);86 } else if (reg_is_gtt(gvt, offset)) {87 offset -= gvt->device_info.gtt_start_offset;88 pt = vgpu->gtt.ggtt_mm->ggtt_mm.virtual_ggtt + offset;89 if (read)90 memcpy(p_data, pt, bytes);91 else92 memcpy(pt, p_data, bytes);93 94 }95 mutex_unlock(&vgpu->vgpu_lock);96}97 98/**99 * intel_vgpu_emulate_mmio_read - emulate MMIO read100 * @vgpu: a vGPU101 * @pa: guest physical address102 * @p_data: data return buffer103 * @bytes: access data length104 *105 * Returns:106 * Zero on success, negative error code if failed107 */108int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa,109 void *p_data, unsigned int bytes)110{111 struct intel_gvt *gvt = vgpu->gvt;112 struct drm_i915_private *i915 = gvt->gt->i915;113 unsigned int offset = 0;114 int ret = -EINVAL;115 116 if (vgpu->failsafe) {117 failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, true);118 return 0;119 }120 mutex_lock(&vgpu->vgpu_lock);121 122 offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa);123 124 if (drm_WARN_ON(&i915->drm, bytes > 8))125 goto err;126 127 if (reg_is_gtt(gvt, offset)) {128 if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4) &&129 !IS_ALIGNED(offset, 8)))130 goto err;131 if (drm_WARN_ON(&i915->drm, bytes != 4 && bytes != 8))132 goto err;133 if (drm_WARN_ON(&i915->drm,134 !reg_is_gtt(gvt, offset + bytes - 1)))135 goto err;136 137 ret = intel_vgpu_emulate_ggtt_mmio_read(vgpu, offset,138 p_data, bytes);139 if (ret)140 goto err;141 goto out;142 }143 144 if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {145 ret = intel_gvt_read_gpa(vgpu, pa, p_data, bytes);146 goto out;147 }148 149 if (drm_WARN_ON(&i915->drm, !reg_is_mmio(gvt, offset + bytes - 1)))150 goto err;151 152 if (!intel_gvt_mmio_is_unalign(gvt, offset)) {153 if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, bytes)))154 goto err;155 }156 157 ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, true);158 if (ret < 0)159 goto err;160 161 intel_gvt_mmio_set_accessed(gvt, offset);162 ret = 0;163 goto out;164 165err:166 gvt_vgpu_err("fail to emulate MMIO read %08x len %d\n",167 offset, bytes);168out:169 mutex_unlock(&vgpu->vgpu_lock);170 return ret;171}172 173/**174 * intel_vgpu_emulate_mmio_write - emulate MMIO write175 * @vgpu: a vGPU176 * @pa: guest physical address177 * @p_data: write data buffer178 * @bytes: access data length179 *180 * Returns:181 * Zero on success, negative error code if failed182 */183int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, u64 pa,184 void *p_data, unsigned int bytes)185{186 struct intel_gvt *gvt = vgpu->gvt;187 struct drm_i915_private *i915 = gvt->gt->i915;188 unsigned int offset = 0;189 int ret = -EINVAL;190 191 if (vgpu->failsafe) {192 failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, false);193 return 0;194 }195 196 mutex_lock(&vgpu->vgpu_lock);197 198 offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa);199 200 if (drm_WARN_ON(&i915->drm, bytes > 8))201 goto err;202 203 if (reg_is_gtt(gvt, offset)) {204 if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4) &&205 !IS_ALIGNED(offset, 8)))206 goto err;207 if (drm_WARN_ON(&i915->drm, bytes != 4 && bytes != 8))208 goto err;209 if (drm_WARN_ON(&i915->drm,210 !reg_is_gtt(gvt, offset + bytes - 1)))211 goto err;212 213 ret = intel_vgpu_emulate_ggtt_mmio_write(vgpu, offset,214 p_data, bytes);215 if (ret)216 goto err;217 goto out;218 }219 220 if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {221 ret = intel_gvt_write_gpa(vgpu, pa, p_data, bytes);222 goto out;223 }224 225 ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, false);226 if (ret < 0)227 goto err;228 229 intel_gvt_mmio_set_accessed(gvt, offset);230 ret = 0;231 goto out;232err:233 gvt_vgpu_err("fail to emulate MMIO write %08x len %d\n", offset,234 bytes);235out:236 mutex_unlock(&vgpu->vgpu_lock);237 return ret;238}239 240 241/**242 * intel_vgpu_reset_mmio - reset virtual MMIO space243 * @vgpu: a vGPU244 * @dmlr: whether this is device model level reset245 */246void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr)247{248 struct intel_gvt *gvt = vgpu->gvt;249 const struct intel_gvt_device_info *info = &gvt->device_info;250 void *mmio = gvt->firmware.mmio;251 252 if (dmlr) {253 memcpy(vgpu->mmio.vreg, mmio, info->mmio_size);254 255 vgpu_vreg_t(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0;256 257 /* set the bit 0:2(Core C-State ) to C0 */258 vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0;259 260 /* uc reset hw expect GS_MIA_IN_RESET */261 vgpu_vreg_t(vgpu, GUC_STATUS) |= GS_MIA_IN_RESET;262 263 if (IS_BROXTON(vgpu->gvt->gt->i915)) {264 vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &=265 ~(BIT(0) | BIT(1));266 vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &=267 ~PHY_POWER_GOOD;268 vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &=269 ~PHY_POWER_GOOD;270 vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &=271 ~BIT(30);272 vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &=273 ~BIT(30);274 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &=275 ~BXT_PHY_LANE_ENABLED;276 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |=277 BXT_PHY_CMNLANE_POWERDOWN_ACK |278 BXT_PHY_LANE_POWERDOWN_ACK;279 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &=280 ~BXT_PHY_LANE_ENABLED;281 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |=282 BXT_PHY_CMNLANE_POWERDOWN_ACK |283 BXT_PHY_LANE_POWERDOWN_ACK;284 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &=285 ~BXT_PHY_LANE_ENABLED;286 vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |=287 BXT_PHY_CMNLANE_POWERDOWN_ACK |288 BXT_PHY_LANE_POWERDOWN_ACK;289 vgpu_vreg_t(vgpu, SKL_FUSE_STATUS) |=290 SKL_FUSE_DOWNLOAD_STATUS |291 SKL_FUSE_PG_DIST_STATUS(SKL_PG0) |292 SKL_FUSE_PG_DIST_STATUS(SKL_PG1) |293 SKL_FUSE_PG_DIST_STATUS(SKL_PG2);294 }295 } else {296#define GVT_GEN8_MMIO_RESET_OFFSET (0x44200)297 /* only reset the engine related, so starting with 0x44200298 * interrupt include DE,display mmio related will not be299 * touched300 */301 memcpy(vgpu->mmio.vreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET);302 }303 304}305 306/**307 * intel_vgpu_init_mmio - init MMIO space308 * @vgpu: a vGPU309 *310 * Returns:311 * Zero on success, negative error code if failed312 */313int intel_vgpu_init_mmio(struct intel_vgpu *vgpu)314{315 const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;316 317 vgpu->mmio.vreg = vzalloc(info->mmio_size);318 if (!vgpu->mmio.vreg)319 return -ENOMEM;320 321 intel_vgpu_reset_mmio(vgpu, true);322 323 return 0;324}325 326/**327 * intel_vgpu_clean_mmio - clean MMIO space328 * @vgpu: a vGPU329 *330 */331void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu)332{333 vfree(vgpu->mmio.vreg);334 vgpu->mmio.vreg = NULL;335}336