1 1.1 riastrad /* $NetBSD: mmio.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice (including the next 14 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 15 1.1 riastrad * Software. 16 1.1 riastrad * 17 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 1.1 riastrad * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 1.1 riastrad * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 1.1 riastrad * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 1.1 riastrad * SOFTWARE. 24 1.1 riastrad * 25 1.1 riastrad * Authors: 26 1.1 riastrad * Ke Yu 27 1.1 riastrad * Kevin Tian <kevin.tian (at) intel.com> 28 1.1 riastrad * Dexuan Cui 29 1.1 riastrad * 30 1.1 riastrad * Contributors: 31 1.1 riastrad * Tina Zhang <tina.zhang (at) intel.com> 32 1.1 riastrad * Min He <min.he (at) intel.com> 33 1.1 riastrad * Niu Bing <bing.niu (at) intel.com> 34 1.1 riastrad * Zhi Wang <zhi.a.wang (at) intel.com> 35 1.1 riastrad * 36 1.1 riastrad */ 37 1.1 riastrad 38 1.1 riastrad #include <sys/cdefs.h> 39 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: mmio.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $"); 40 1.1 riastrad 41 1.1 riastrad #include "i915_drv.h" 42 1.1 riastrad #include "gvt.h" 43 1.1 riastrad 44 1.1 riastrad /** 45 1.1 riastrad * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset 46 1.1 riastrad * @vgpu: a vGPU 47 1.1 riastrad * @gpa: guest physical address 48 1.1 riastrad * 49 1.1 riastrad * Returns: 50 1.1 riastrad * Zero on success, negative error code if failed 51 1.1 riastrad */ 52 1.1 riastrad int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa) 53 1.1 riastrad { 54 1.1 riastrad u64 gttmmio_gpa = intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0); 55 1.1 riastrad return gpa - gttmmio_gpa; 56 1.1 riastrad } 57 1.1 riastrad 58 1.1 riastrad #define reg_is_mmio(gvt, reg) \ 59 1.1 riastrad (reg >= 0 && reg < gvt->device_info.mmio_size) 60 1.1 riastrad 61 1.1 riastrad #define reg_is_gtt(gvt, reg) \ 62 1.1 riastrad (reg >= gvt->device_info.gtt_start_offset \ 63 1.1 riastrad && reg < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) 64 1.1 riastrad 65 1.1 riastrad static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, u64 pa, 66 1.1 riastrad void *p_data, unsigned int bytes, bool read) 67 1.1 riastrad { 68 1.1 riastrad struct intel_gvt *gvt = NULL; 69 1.1 riastrad void *pt = NULL; 70 1.1 riastrad unsigned int offset = 0; 71 1.1 riastrad 72 1.1 riastrad if (!vgpu || !p_data) 73 1.1 riastrad return; 74 1.1 riastrad 75 1.1 riastrad gvt = vgpu->gvt; 76 1.1 riastrad mutex_lock(&vgpu->vgpu_lock); 77 1.1 riastrad offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); 78 1.1 riastrad if (reg_is_mmio(gvt, offset)) { 79 1.1 riastrad if (read) 80 1.1 riastrad intel_vgpu_default_mmio_read(vgpu, offset, p_data, 81 1.1 riastrad bytes); 82 1.1 riastrad else 83 1.1 riastrad intel_vgpu_default_mmio_write(vgpu, offset, p_data, 84 1.1 riastrad bytes); 85 1.1 riastrad } else if (reg_is_gtt(gvt, offset)) { 86 1.1 riastrad offset -= gvt->device_info.gtt_start_offset; 87 1.1 riastrad pt = vgpu->gtt.ggtt_mm->ggtt_mm.virtual_ggtt + offset; 88 1.1 riastrad if (read) 89 1.1 riastrad memcpy(p_data, pt, bytes); 90 1.1 riastrad else 91 1.1 riastrad memcpy(pt, p_data, bytes); 92 1.1 riastrad 93 1.1 riastrad } 94 1.1 riastrad mutex_unlock(&vgpu->vgpu_lock); 95 1.1 riastrad } 96 1.1 riastrad 97 1.1 riastrad /** 98 1.1 riastrad * intel_vgpu_emulate_mmio_read - emulate MMIO read 99 1.1 riastrad * @vgpu: a vGPU 100 1.1 riastrad * @pa: guest physical address 101 1.1 riastrad * @p_data: data return buffer 102 1.1 riastrad * @bytes: access data length 103 1.1 riastrad * 104 1.1 riastrad * Returns: 105 1.1 riastrad * Zero on success, negative error code if failed 106 1.1 riastrad */ 107 1.1 riastrad int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa, 108 1.1 riastrad void *p_data, unsigned int bytes) 109 1.1 riastrad { 110 1.1 riastrad struct intel_gvt *gvt = vgpu->gvt; 111 1.1 riastrad unsigned int offset = 0; 112 1.1 riastrad int ret = -EINVAL; 113 1.1 riastrad 114 1.1 riastrad if (vgpu->failsafe) { 115 1.1 riastrad failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, true); 116 1.1 riastrad return 0; 117 1.1 riastrad } 118 1.1 riastrad mutex_lock(&vgpu->vgpu_lock); 119 1.1 riastrad 120 1.1 riastrad offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); 121 1.1 riastrad 122 1.1 riastrad if (WARN_ON(bytes > 8)) 123 1.1 riastrad goto err; 124 1.1 riastrad 125 1.1 riastrad if (reg_is_gtt(gvt, offset)) { 126 1.1 riastrad if (WARN_ON(!IS_ALIGNED(offset, 4) && !IS_ALIGNED(offset, 8))) 127 1.1 riastrad goto err; 128 1.1 riastrad if (WARN_ON(bytes != 4 && bytes != 8)) 129 1.1 riastrad goto err; 130 1.1 riastrad if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1))) 131 1.1 riastrad goto err; 132 1.1 riastrad 133 1.1 riastrad ret = intel_vgpu_emulate_ggtt_mmio_read(vgpu, offset, 134 1.1 riastrad p_data, bytes); 135 1.1 riastrad if (ret) 136 1.1 riastrad goto err; 137 1.1 riastrad goto out; 138 1.1 riastrad } 139 1.1 riastrad 140 1.1 riastrad if (WARN_ON_ONCE(!reg_is_mmio(gvt, offset))) { 141 1.1 riastrad ret = intel_gvt_hypervisor_read_gpa(vgpu, pa, p_data, bytes); 142 1.1 riastrad goto out; 143 1.1 riastrad } 144 1.1 riastrad 145 1.1 riastrad if (WARN_ON(!reg_is_mmio(gvt, offset + bytes - 1))) 146 1.1 riastrad goto err; 147 1.1 riastrad 148 1.1 riastrad if (!intel_gvt_mmio_is_unalign(gvt, offset)) { 149 1.1 riastrad if (WARN_ON(!IS_ALIGNED(offset, bytes))) 150 1.1 riastrad goto err; 151 1.1 riastrad } 152 1.1 riastrad 153 1.1 riastrad ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, true); 154 1.1 riastrad if (ret < 0) 155 1.1 riastrad goto err; 156 1.1 riastrad 157 1.1 riastrad intel_gvt_mmio_set_accessed(gvt, offset); 158 1.1 riastrad ret = 0; 159 1.1 riastrad goto out; 160 1.1 riastrad 161 1.1 riastrad err: 162 1.1 riastrad gvt_vgpu_err("fail to emulate MMIO read %08x len %d\n", 163 1.1 riastrad offset, bytes); 164 1.1 riastrad out: 165 1.1 riastrad mutex_unlock(&vgpu->vgpu_lock); 166 1.1 riastrad return ret; 167 1.1 riastrad } 168 1.1 riastrad 169 1.1 riastrad /** 170 1.1 riastrad * intel_vgpu_emulate_mmio_write - emulate MMIO write 171 1.1 riastrad * @vgpu: a vGPU 172 1.1 riastrad * @pa: guest physical address 173 1.1 riastrad * @p_data: write data buffer 174 1.1 riastrad * @bytes: access data length 175 1.1 riastrad * 176 1.1 riastrad * Returns: 177 1.1 riastrad * Zero on success, negative error code if failed 178 1.1 riastrad */ 179 1.1 riastrad int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, u64 pa, 180 1.1 riastrad void *p_data, unsigned int bytes) 181 1.1 riastrad { 182 1.1 riastrad struct intel_gvt *gvt = vgpu->gvt; 183 1.1 riastrad unsigned int offset = 0; 184 1.1 riastrad int ret = -EINVAL; 185 1.1 riastrad 186 1.1 riastrad if (vgpu->failsafe) { 187 1.1 riastrad failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, false); 188 1.1 riastrad return 0; 189 1.1 riastrad } 190 1.1 riastrad 191 1.1 riastrad mutex_lock(&vgpu->vgpu_lock); 192 1.1 riastrad 193 1.1 riastrad offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); 194 1.1 riastrad 195 1.1 riastrad if (WARN_ON(bytes > 8)) 196 1.1 riastrad goto err; 197 1.1 riastrad 198 1.1 riastrad if (reg_is_gtt(gvt, offset)) { 199 1.1 riastrad if (WARN_ON(!IS_ALIGNED(offset, 4) && !IS_ALIGNED(offset, 8))) 200 1.1 riastrad goto err; 201 1.1 riastrad if (WARN_ON(bytes != 4 && bytes != 8)) 202 1.1 riastrad goto err; 203 1.1 riastrad if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1))) 204 1.1 riastrad goto err; 205 1.1 riastrad 206 1.1 riastrad ret = intel_vgpu_emulate_ggtt_mmio_write(vgpu, offset, 207 1.1 riastrad p_data, bytes); 208 1.1 riastrad if (ret) 209 1.1 riastrad goto err; 210 1.1 riastrad goto out; 211 1.1 riastrad } 212 1.1 riastrad 213 1.1 riastrad if (WARN_ON_ONCE(!reg_is_mmio(gvt, offset))) { 214 1.1 riastrad ret = intel_gvt_hypervisor_write_gpa(vgpu, pa, p_data, bytes); 215 1.1 riastrad goto out; 216 1.1 riastrad } 217 1.1 riastrad 218 1.1 riastrad ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, false); 219 1.1 riastrad if (ret < 0) 220 1.1 riastrad goto err; 221 1.1 riastrad 222 1.1 riastrad intel_gvt_mmio_set_accessed(gvt, offset); 223 1.1 riastrad ret = 0; 224 1.1 riastrad goto out; 225 1.1 riastrad err: 226 1.1 riastrad gvt_vgpu_err("fail to emulate MMIO write %08x len %d\n", offset, 227 1.1 riastrad bytes); 228 1.1 riastrad out: 229 1.1 riastrad mutex_unlock(&vgpu->vgpu_lock); 230 1.1 riastrad return ret; 231 1.1 riastrad } 232 1.1 riastrad 233 1.1 riastrad 234 1.1 riastrad /** 235 1.1 riastrad * intel_vgpu_reset_mmio - reset virtual MMIO space 236 1.1 riastrad * @vgpu: a vGPU 237 1.1 riastrad * @dmlr: whether this is device model level reset 238 1.1 riastrad */ 239 1.1 riastrad void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr) 240 1.1 riastrad { 241 1.1 riastrad struct intel_gvt *gvt = vgpu->gvt; 242 1.1 riastrad const struct intel_gvt_device_info *info = &gvt->device_info; 243 1.1 riastrad void *mmio = gvt->firmware.mmio; 244 1.1 riastrad 245 1.1 riastrad if (dmlr) { 246 1.1 riastrad memcpy(vgpu->mmio.vreg, mmio, info->mmio_size); 247 1.1 riastrad 248 1.1 riastrad vgpu_vreg_t(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0; 249 1.1 riastrad 250 1.1 riastrad /* set the bit 0:2(Core C-State ) to C0 */ 251 1.1 riastrad vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0; 252 1.1 riastrad 253 1.1 riastrad if (IS_BROXTON(vgpu->gvt->dev_priv)) { 254 1.1 riastrad vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= 255 1.1 riastrad ~(BIT(0) | BIT(1)); 256 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &= 257 1.1 riastrad ~PHY_POWER_GOOD; 258 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &= 259 1.1 riastrad ~PHY_POWER_GOOD; 260 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &= 261 1.1 riastrad ~BIT(30); 262 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &= 263 1.1 riastrad ~BIT(30); 264 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &= 265 1.1 riastrad ~BXT_PHY_LANE_ENABLED; 266 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |= 267 1.1 riastrad BXT_PHY_CMNLANE_POWERDOWN_ACK | 268 1.1 riastrad BXT_PHY_LANE_POWERDOWN_ACK; 269 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &= 270 1.1 riastrad ~BXT_PHY_LANE_ENABLED; 271 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |= 272 1.1 riastrad BXT_PHY_CMNLANE_POWERDOWN_ACK | 273 1.1 riastrad BXT_PHY_LANE_POWERDOWN_ACK; 274 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &= 275 1.1 riastrad ~BXT_PHY_LANE_ENABLED; 276 1.1 riastrad vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |= 277 1.1 riastrad BXT_PHY_CMNLANE_POWERDOWN_ACK | 278 1.1 riastrad BXT_PHY_LANE_POWERDOWN_ACK; 279 1.1 riastrad } 280 1.1 riastrad } else { 281 1.1 riastrad #define GVT_GEN8_MMIO_RESET_OFFSET (0x44200) 282 1.1 riastrad /* only reset the engine related, so starting with 0x44200 283 1.1 riastrad * interrupt include DE,display mmio related will not be 284 1.1 riastrad * touched 285 1.1 riastrad */ 286 1.1 riastrad memcpy(vgpu->mmio.vreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET); 287 1.1 riastrad } 288 1.1 riastrad 289 1.1 riastrad } 290 1.1 riastrad 291 1.1 riastrad /** 292 1.1 riastrad * intel_vgpu_init_mmio - init MMIO space 293 1.1 riastrad * @vgpu: a vGPU 294 1.1 riastrad * 295 1.1 riastrad * Returns: 296 1.1 riastrad * Zero on success, negative error code if failed 297 1.1 riastrad */ 298 1.1 riastrad int intel_vgpu_init_mmio(struct intel_vgpu *vgpu) 299 1.1 riastrad { 300 1.1 riastrad const struct intel_gvt_device_info *info = &vgpu->gvt->device_info; 301 1.1 riastrad 302 1.1 riastrad vgpu->mmio.vreg = vzalloc(info->mmio_size); 303 1.1 riastrad if (!vgpu->mmio.vreg) 304 1.1 riastrad return -ENOMEM; 305 1.1 riastrad 306 1.1 riastrad intel_vgpu_reset_mmio(vgpu, true); 307 1.1 riastrad 308 1.1 riastrad return 0; 309 1.1 riastrad } 310 1.1 riastrad 311 1.1 riastrad /** 312 1.1 riastrad * intel_vgpu_clean_mmio - clean MMIO space 313 1.1 riastrad * @vgpu: a vGPU 314 1.1 riastrad * 315 1.1 riastrad */ 316 1.1 riastrad void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu) 317 1.1 riastrad { 318 1.1 riastrad vfree(vgpu->mmio.vreg); 319 1.1 riastrad vgpu->mmio.vreg = NULL; 320 1.1 riastrad } 321