File Index
Files and directories
Sign in
FILE

mmio.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/i915/gvt/mmio.c 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 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 <linux/vmalloc.h>
 37
 38#include <drm/drm_print.h>
 39
 40#include "i915_drv.h"
 41#include "i915_reg.h"
 42#include "display/intel_display_regs.h"
 43#include "gvt.h"
 44
 45#include "display/bxt_dpio_phy_regs.h"
 46#include "display/intel_dpio_phy.h"
 47#include "gt/intel_gt_regs.h"
 48
 49/**
 50 * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset
 51 * @vgpu: a vGPU
 52 * @gpa: guest physical address
 53 *
 54 * Returns:
 55 * The MMIO offset of the given GPA
 56 */
 57int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa)
 58{
 59	u64 gttmmio_gpa = intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0);
 60	return gpa - gttmmio_gpa;
 61}
 62
 63#define reg_is_mmio(gvt, reg)  \
 64	(reg < gvt->device_info.mmio_size)
 65
 66#define reg_is_gtt(gvt, reg)   \
 67	(reg >= gvt->device_info.gtt_start_offset \
 68	 && reg < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt))
 69
 70static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, u64 pa,
 71		void *p_data, unsigned int bytes, bool read)
 72{
 73	struct intel_gvt *gvt = NULL;
 74	void *pt = NULL;
 75	unsigned int offset = 0;
 76
 77	if (!vgpu || !p_data)
 78		return;
 79
 80	gvt = vgpu->gvt;
 81	mutex_lock(&vgpu->vgpu_lock);
 82	offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa);
 83	if (reg_is_mmio(gvt, offset)) {
 84		if (read)
 85			intel_vgpu_default_mmio_read(vgpu, offset, p_data,
 86					bytes);
 87		else
 88			intel_vgpu_default_mmio_write(vgpu, offset, p_data,
 89					bytes);
 90	} else if (reg_is_gtt(gvt, offset)) {
 91		offset -= gvt->device_info.gtt_start_offset;
 92		pt = vgpu->gtt.ggtt_mm->ggtt_mm.virtual_ggtt + offset;
 93		if (read)
 94			memcpy(p_data, pt, bytes);
 95		else
 96			memcpy(pt, p_data, bytes);
 97
 98	}
 99	mutex_unlock(&vgpu->vgpu_lock);
100}
101
102/**
103 * intel_vgpu_emulate_mmio_read - emulate MMIO read
104 * @vgpu: a vGPU
105 * @pa: guest physical address
106 * @p_data: data return buffer
107 * @bytes: access data length
108 *
109 * Returns:
110 * Zero on success, negative error code if failed
111 */
112int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa,
113		void *p_data, unsigned int bytes)
114{
115	struct intel_gvt *gvt = vgpu->gvt;
116	struct drm_i915_private *i915 = gvt->gt->i915;
117	unsigned int offset = 0;
118	int ret = -EINVAL;
119
120	if (vgpu->failsafe) {
121		failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, true);
122		return 0;
123	}
124	mutex_lock(&vgpu->vgpu_lock);
125
126	offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa);
127
128	if (drm_WARN_ON(&i915->drm, bytes > 8))
129		goto err;
130
131	if (reg_is_gtt(gvt, offset)) {
132		if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4) &&
133				!IS_ALIGNED(offset, 8)))
134			goto err;
135		if (drm_WARN_ON(&i915->drm, bytes != 4 && bytes != 8))
136			goto err;
137		if (drm_WARN_ON(&i915->drm,
138				!reg_is_gtt(gvt, offset + bytes - 1)))
139			goto err;
140
141		ret = intel_vgpu_emulate_ggtt_mmio_read(vgpu, offset,
142				p_data, bytes);
143		if (ret)
144			goto err;
145		goto out;
146	}
147
148	if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {
149		ret = intel_gvt_read_gpa(vgpu, pa, p_data, bytes);
150		goto out;
151	}
152
153	if (drm_WARN_ON(&i915->drm, !reg_is_mmio(gvt, offset + bytes - 1)))
154		goto err;
155
156	if (!intel_gvt_mmio_is_unalign(gvt, offset)) {
157		if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, bytes)))
158			goto err;
159	}
160
161	ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, true);
162	if (ret < 0)
163		goto err;
164
165	intel_gvt_mmio_set_accessed(gvt, offset);
166	ret = 0;
167	goto out;
168
169err:
170	gvt_vgpu_err("fail to emulate MMIO read %08x len %d\n",
171			offset, bytes);
172out:
173	mutex_unlock(&vgpu->vgpu_lock);
174	return ret;
175}
176
177/**
178 * intel_vgpu_emulate_mmio_write - emulate MMIO write
179 * @vgpu: a vGPU
180 * @pa: guest physical address
181 * @p_data: write data buffer
182 * @bytes: access data length
183 *
184 * Returns:
185 * Zero on success, negative error code if failed
186 */
187int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, u64 pa,
188		void *p_data, unsigned int bytes)
189{
190	struct intel_gvt *gvt = vgpu->gvt;
191	struct drm_i915_private *i915 = gvt->gt->i915;
192	unsigned int offset = 0;
193	int ret = -EINVAL;
194
195	if (vgpu->failsafe) {
196		failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, false);
197		return 0;
198	}
199
200	mutex_lock(&vgpu->vgpu_lock);
201
202	offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa);
203
204	if (drm_WARN_ON(&i915->drm, bytes > 8))
205		goto err;
206
207	if (reg_is_gtt(gvt, offset)) {
208		if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4) &&
209				!IS_ALIGNED(offset, 8)))
210			goto err;
211		if (drm_WARN_ON(&i915->drm, bytes != 4 && bytes != 8))
212			goto err;
213		if (drm_WARN_ON(&i915->drm,
214				!reg_is_gtt(gvt, offset + bytes - 1)))
215			goto err;
216
217		ret = intel_vgpu_emulate_ggtt_mmio_write(vgpu, offset,
218				p_data, bytes);
219		if (ret)
220			goto err;
221		goto out;
222	}
223
224	if (drm_WARN_ON_ONCE(&i915->drm, !reg_is_mmio(gvt, offset))) {
225		ret = intel_gvt_write_gpa(vgpu, pa, p_data, bytes);
226		goto out;
227	}
228
229	ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, false);
230	if (ret < 0)
231		goto err;
232
233	intel_gvt_mmio_set_accessed(gvt, offset);
234	ret = 0;
235	goto out;
236err:
237	gvt_vgpu_err("fail to emulate MMIO write %08x len %d\n", offset,
238		     bytes);
239out:
240	mutex_unlock(&vgpu->vgpu_lock);
241	return ret;
242}
243
244
245/**
246 * intel_vgpu_reset_mmio - reset virtual MMIO space
247 * @vgpu: a vGPU
248 * @dmlr: whether this is device model level reset
249 */
250void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr)
251{
252	struct intel_gvt *gvt = vgpu->gvt;
253	const struct intel_gvt_device_info *info = &gvt->device_info;
254	void  *mmio = gvt->firmware.mmio;
255
256	if (dmlr) {
257		memcpy(vgpu->mmio.vreg, mmio, info->mmio_size);
258
259		vgpu_vreg_t(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0;
260
261		/* set the bit 0:2(Core C-State ) to C0 */
262		vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0;
263
264		/* uc reset hw expect GS_MIA_IN_RESET */
265		vgpu_vreg_t(vgpu, GUC_STATUS) |= GS_MIA_IN_RESET;
266
267		if (IS_BROXTON(vgpu->gvt->gt->i915)) {
268			vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &=
269				    ~(BIT(0) | BIT(1));
270			vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &=
271				    ~PHY_POWER_GOOD;
272			vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &=
273				    ~PHY_POWER_GOOD;
274			vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &=
275				    ~BIT(30);
276			vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &=
277				    ~BIT(30);
278			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &=
279				    ~BXT_PHY_LANE_ENABLED;
280			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |=
281				    BXT_PHY_CMNLANE_POWERDOWN_ACK |
282				    BXT_PHY_LANE_POWERDOWN_ACK;
283			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &=
284				    ~BXT_PHY_LANE_ENABLED;
285			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |=
286				    BXT_PHY_CMNLANE_POWERDOWN_ACK |
287				    BXT_PHY_LANE_POWERDOWN_ACK;
288			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &=
289				    ~BXT_PHY_LANE_ENABLED;
290			vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |=
291				    BXT_PHY_CMNLANE_POWERDOWN_ACK |
292				    BXT_PHY_LANE_POWERDOWN_ACK;
293			vgpu_vreg_t(vgpu, SKL_FUSE_STATUS) |=
294				SKL_FUSE_DOWNLOAD_STATUS |
295				SKL_FUSE_PG_DIST_STATUS(SKL_PG0) |
296				SKL_FUSE_PG_DIST_STATUS(SKL_PG1) |
297				SKL_FUSE_PG_DIST_STATUS(SKL_PG2);
298		}
299	} else {
300#define GVT_GEN8_MMIO_RESET_OFFSET		(0x44200)
301		/* only reset the engine related, so starting with 0x44200
302		 * interrupt include DE,display mmio related will not be
303		 * touched
304		 */
305		memcpy(vgpu->mmio.vreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET);
306	}
307
308}
309
310/**
311 * intel_vgpu_init_mmio - init MMIO  space
312 * @vgpu: a vGPU
313 *
314 * Returns:
315 * Zero on success, negative error code if failed
316 */
317int intel_vgpu_init_mmio(struct intel_vgpu *vgpu)
318{
319	const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
320
321	vgpu->mmio.vreg = vzalloc(info->mmio_size);
322	if (!vgpu->mmio.vreg)
323		return -ENOMEM;
324
325	intel_vgpu_reset_mmio(vgpu, true);
326
327	return 0;
328}
329
330/**
331 * intel_vgpu_clean_mmio - clean MMIO space
332 * @vgpu: a vGPU
333 *
334 */
335void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu)
336{
337	vfree(vgpu->mmio.vreg);
338	vgpu->mmio.vreg = NULL;
339}
~/ Read-only file preview.