Home | History | Annotate | Line # | Download | only in gvt
      1 /*	$NetBSD: cfg_space.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * Authors:
     26  *    Eddie Dong <eddie.dong (at) intel.com>
     27  *    Jike Song <jike.song (at) intel.com>
     28  *
     29  * Contributors:
     30  *    Zhi Wang <zhi.a.wang (at) intel.com>
     31  *    Min He <min.he (at) intel.com>
     32  *    Bing Niu <bing.niu (at) intel.com>
     33  *
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: cfg_space.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $");
     38 
     39 #include "i915_drv.h"
     40 #include "gvt.h"
     41 
     42 enum {
     43 	INTEL_GVT_PCI_BAR_GTTMMIO = 0,
     44 	INTEL_GVT_PCI_BAR_APERTURE,
     45 	INTEL_GVT_PCI_BAR_PIO,
     46 	INTEL_GVT_PCI_BAR_MAX,
     47 };
     48 
     49 /* bitmap for writable bits (RW or RW1C bits, but cannot co-exist in one
     50  * byte) byte by byte in standard pci configuration space. (not the full
     51  * 256 bytes.)
     52  */
     53 static const u8 pci_cfg_space_rw_bmp[PCI_INTERRUPT_LINE + 4] = {
     54 	[PCI_COMMAND]		= 0xff, 0x07,
     55 	[PCI_STATUS]		= 0x00, 0xf9, /* the only one RW1C byte */
     56 	[PCI_CACHE_LINE_SIZE]	= 0xff,
     57 	[PCI_BASE_ADDRESS_0 ... PCI_CARDBUS_CIS - 1] = 0xff,
     58 	[PCI_ROM_ADDRESS]	= 0x01, 0xf8, 0xff, 0xff,
     59 	[PCI_INTERRUPT_LINE]	= 0xff,
     60 };
     61 
     62 /**
     63  * vgpu_pci_cfg_mem_write - write virtual cfg space memory
     64  * @vgpu: target vgpu
     65  * @off: offset
     66  * @src: src ptr to write
     67  * @bytes: number of bytes
     68  *
     69  * Use this function to write virtual cfg space memory.
     70  * For standard cfg space, only RW bits can be changed,
     71  * and we emulates the RW1C behavior of PCI_STATUS register.
     72  */
     73 static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off,
     74 				   u8 *src, unsigned int bytes)
     75 {
     76 	u8 *cfg_base = vgpu_cfg_space(vgpu);
     77 	u8 mask, new, old;
     78 	int i = 0;
     79 
     80 	for (; i < bytes && (off + i < sizeof(pci_cfg_space_rw_bmp)); i++) {
     81 		mask = pci_cfg_space_rw_bmp[off + i];
     82 		old = cfg_base[off + i];
     83 		new = src[i] & mask;
     84 
     85 		/**
     86 		 * The PCI_STATUS high byte has RW1C bits, here
     87 		 * emulates clear by writing 1 for these bits.
     88 		 * Writing a 0b to RW1C bits has no effect.
     89 		 */
     90 		if (off + i == PCI_STATUS + 1)
     91 			new = (~new & old) & mask;
     92 
     93 		cfg_base[off + i] = (old & ~mask) | new;
     94 	}
     95 
     96 	/* For other configuration space directly copy as it is. */
     97 	if (i < bytes)
     98 		memcpy(cfg_base + off + i, src + i, bytes - i);
     99 }
    100 
    101 /**
    102  * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space read
    103  * @vgpu: target vgpu
    104  * @offset: offset
    105  * @p_data: return data ptr
    106  * @bytes: number of bytes to read
    107  *
    108  * Returns:
    109  * Zero on success, negative error code if failed.
    110  */
    111 int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,
    112 	void *p_data, unsigned int bytes)
    113 {
    114 	if (WARN_ON(bytes > 4))
    115 		return -EINVAL;
    116 
    117 	if (WARN_ON(offset + bytes > vgpu->gvt->device_info.cfg_space_size))
    118 		return -EINVAL;
    119 
    120 	memcpy(p_data, vgpu_cfg_space(vgpu) + offset, bytes);
    121 	return 0;
    122 }
    123 
    124 static int map_aperture(struct intel_vgpu *vgpu, bool map)
    125 {
    126 	phys_addr_t aperture_pa = vgpu_aperture_pa_base(vgpu);
    127 	unsigned long aperture_sz = vgpu_aperture_sz(vgpu);
    128 	u64 first_gfn;
    129 	u64 val;
    130 	int ret;
    131 
    132 	if (map == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked)
    133 		return 0;
    134 
    135 	val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_2];
    136 	if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
    137 		val = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
    138 	else
    139 		val = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
    140 
    141 	first_gfn = (val + vgpu_aperture_offset(vgpu)) >> PAGE_SHIFT;
    142 
    143 	ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, first_gfn,
    144 						  aperture_pa >> PAGE_SHIFT,
    145 						  aperture_sz >> PAGE_SHIFT,
    146 						  map);
    147 	if (ret)
    148 		return ret;
    149 
    150 	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map;
    151 	return 0;
    152 }
    153 
    154 static int trap_gttmmio(struct intel_vgpu *vgpu, bool trap)
    155 {
    156 	u64 start, end;
    157 	u64 val;
    158 	int ret;
    159 
    160 	if (trap == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked)
    161 		return 0;
    162 
    163 	val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_0];
    164 	if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
    165 		start = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
    166 	else
    167 		start = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
    168 
    169 	start &= ~GENMASK(3, 0);
    170 	end = start + vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size - 1;
    171 
    172 	ret = intel_gvt_hypervisor_set_trap_area(vgpu, start, end, trap);
    173 	if (ret)
    174 		return ret;
    175 
    176 	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked = trap;
    177 	return 0;
    178 }
    179 
    180 static int emulate_pci_command_write(struct intel_vgpu *vgpu,
    181 	unsigned int offset, void *p_data, unsigned int bytes)
    182 {
    183 	u8 old = vgpu_cfg_space(vgpu)[offset];
    184 	u8 new = *(u8 *)p_data;
    185 	u8 changed = old ^ new;
    186 	int ret;
    187 
    188 	vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
    189 	if (!(changed & PCI_COMMAND_MEMORY))
    190 		return 0;
    191 
    192 	if (old & PCI_COMMAND_MEMORY) {
    193 		ret = trap_gttmmio(vgpu, false);
    194 		if (ret)
    195 			return ret;
    196 		ret = map_aperture(vgpu, false);
    197 		if (ret)
    198 			return ret;
    199 	} else {
    200 		ret = trap_gttmmio(vgpu, true);
    201 		if (ret)
    202 			return ret;
    203 		ret = map_aperture(vgpu, true);
    204 		if (ret)
    205 			return ret;
    206 	}
    207 
    208 	return 0;
    209 }
    210 
    211 static int emulate_pci_rom_bar_write(struct intel_vgpu *vgpu,
    212 	unsigned int offset, void *p_data, unsigned int bytes)
    213 {
    214 	u32 *pval = (u32 *)(vgpu_cfg_space(vgpu) + offset);
    215 	u32 new = *(u32 *)(p_data);
    216 
    217 	if ((new & PCI_ROM_ADDRESS_MASK) == PCI_ROM_ADDRESS_MASK)
    218 		/* We don't have rom, return size of 0. */
    219 		*pval = 0;
    220 	else
    221 		vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
    222 	return 0;
    223 }
    224 
    225 static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
    226 	void *p_data, unsigned int bytes)
    227 {
    228 	u32 new = *(u32 *)(p_data);
    229 	bool lo = IS_ALIGNED(offset, 8);
    230 	u64 size;
    231 	int ret = 0;
    232 	bool mmio_enabled =
    233 		vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY;
    234 	struct intel_vgpu_pci_bar *bars = vgpu->cfg_space.bar;
    235 
    236 	/*
    237 	 * Power-up software can determine how much address
    238 	 * space the device requires by writing a value of
    239 	 * all 1's to the register and then reading the value
    240 	 * back. The device will return 0's in all don't-care
    241 	 * address bits.
    242 	 */
    243 	if (new == 0xffffffff) {
    244 		switch (offset) {
    245 		case PCI_BASE_ADDRESS_0:
    246 		case PCI_BASE_ADDRESS_1:
    247 			size = ~(bars[INTEL_GVT_PCI_BAR_GTTMMIO].size -1);
    248 			intel_vgpu_write_pci_bar(vgpu, offset,
    249 						size >> (lo ? 0 : 32), lo);
    250 			/*
    251 			 * Untrap the BAR, since guest hasn't configured a
    252 			 * valid GPA
    253 			 */
    254 			ret = trap_gttmmio(vgpu, false);
    255 			break;
    256 		case PCI_BASE_ADDRESS_2:
    257 		case PCI_BASE_ADDRESS_3:
    258 			size = ~(bars[INTEL_GVT_PCI_BAR_APERTURE].size -1);
    259 			intel_vgpu_write_pci_bar(vgpu, offset,
    260 						size >> (lo ? 0 : 32), lo);
    261 			ret = map_aperture(vgpu, false);
    262 			break;
    263 		default:
    264 			/* Unimplemented BARs */
    265 			intel_vgpu_write_pci_bar(vgpu, offset, 0x0, false);
    266 		}
    267 	} else {
    268 		switch (offset) {
    269 		case PCI_BASE_ADDRESS_0:
    270 		case PCI_BASE_ADDRESS_1:
    271 			/*
    272 			 * Untrap the old BAR first, since guest has
    273 			 * re-configured the BAR
    274 			 */
    275 			trap_gttmmio(vgpu, false);
    276 			intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
    277 			ret = trap_gttmmio(vgpu, mmio_enabled);
    278 			break;
    279 		case PCI_BASE_ADDRESS_2:
    280 		case PCI_BASE_ADDRESS_3:
    281 			map_aperture(vgpu, false);
    282 			intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
    283 			ret = map_aperture(vgpu, mmio_enabled);
    284 			break;
    285 		default:
    286 			intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
    287 		}
    288 	}
    289 	return ret;
    290 }
    291 
    292 /**
    293  * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space write
    294  * @vgpu: target vgpu
    295  * @offset: offset
    296  * @p_data: write data ptr
    297  * @bytes: number of bytes to write
    298  *
    299  * Returns:
    300  * Zero on success, negative error code if failed.
    301  */
    302 int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
    303 	void *p_data, unsigned int bytes)
    304 {
    305 	int ret;
    306 
    307 	if (WARN_ON(bytes > 4))
    308 		return -EINVAL;
    309 
    310 	if (WARN_ON(offset + bytes > vgpu->gvt->device_info.cfg_space_size))
    311 		return -EINVAL;
    312 
    313 	/* First check if it's PCI_COMMAND */
    314 	if (IS_ALIGNED(offset, 2) && offset == PCI_COMMAND) {
    315 		if (WARN_ON(bytes > 2))
    316 			return -EINVAL;
    317 		return emulate_pci_command_write(vgpu, offset, p_data, bytes);
    318 	}
    319 
    320 	switch (rounddown(offset, 4)) {
    321 	case PCI_ROM_ADDRESS:
    322 		if (WARN_ON(!IS_ALIGNED(offset, 4)))
    323 			return -EINVAL;
    324 		return emulate_pci_rom_bar_write(vgpu, offset, p_data, bytes);
    325 
    326 	case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:
    327 		if (WARN_ON(!IS_ALIGNED(offset, 4)))
    328 			return -EINVAL;
    329 		return emulate_pci_bar_write(vgpu, offset, p_data, bytes);
    330 
    331 	case INTEL_GVT_PCI_SWSCI:
    332 		if (WARN_ON(!IS_ALIGNED(offset, 4)))
    333 			return -EINVAL;
    334 		ret = intel_vgpu_emulate_opregion_request(vgpu, *(u32 *)p_data);
    335 		if (ret)
    336 			return ret;
    337 		break;
    338 
    339 	case INTEL_GVT_PCI_OPREGION:
    340 		if (WARN_ON(!IS_ALIGNED(offset, 4)))
    341 			return -EINVAL;
    342 		ret = intel_vgpu_opregion_base_write_handler(vgpu,
    343 						   *(u32 *)p_data);
    344 		if (ret)
    345 			return ret;
    346 
    347 		vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
    348 		break;
    349 	default:
    350 		vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
    351 		break;
    352 	}
    353 	return 0;
    354 }
    355 
    356 /**
    357  * intel_vgpu_init_cfg_space - init vGPU configuration space when create vGPU
    358  *
    359  * @vgpu: a vGPU
    360  * @primary: is the vGPU presented as primary
    361  *
    362  */
    363 void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
    364 			       bool primary)
    365 {
    366 	struct intel_gvt *gvt = vgpu->gvt;
    367 	const struct intel_gvt_device_info *info = &gvt->device_info;
    368 	u16 *gmch_ctl;
    369 
    370 	memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
    371 	       info->cfg_space_size);
    372 
    373 	if (!primary) {
    374 		vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] =
    375 			INTEL_GVT_PCI_CLASS_VGA_OTHER;
    376 		vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] =
    377 			INTEL_GVT_PCI_CLASS_VGA_OTHER;
    378 	}
    379 
    380 	/* Show guest that there isn't any stolen memory.*/
    381 	gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL);
    382 	*gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT);
    383 
    384 	intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2,
    385 				 gvt_aperture_pa_base(gvt), true);
    386 
    387 	vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO
    388 					     | PCI_COMMAND_MEMORY
    389 					     | PCI_COMMAND_MASTER);
    390 	/*
    391 	 * Clear the bar upper 32bit and let guest to assign the new value
    392 	 */
    393 	memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
    394 	memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
    395 	memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_4, 0, 8);
    396 	memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
    397 
    398 	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size =
    399 				pci_resource_len(gvt->dev_priv->drm.pdev, 0);
    400 	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size =
    401 				pci_resource_len(gvt->dev_priv->drm.pdev, 2);
    402 
    403 	memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4);
    404 }
    405 
    406 /**
    407  * intel_vgpu_reset_cfg_space - reset vGPU configuration space
    408  *
    409  * @vgpu: a vGPU
    410  *
    411  */
    412 void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu)
    413 {
    414 	u8 cmd = vgpu_cfg_space(vgpu)[PCI_COMMAND];
    415 	bool primary = vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] !=
    416 				INTEL_GVT_PCI_CLASS_VGA_OTHER;
    417 
    418 	if (cmd & PCI_COMMAND_MEMORY) {
    419 		trap_gttmmio(vgpu, false);
    420 		map_aperture(vgpu, false);
    421 	}
    422 
    423 	/**
    424 	 * Currently we only do such reset when vGPU is not
    425 	 * owned by any VM, so we simply restore entire cfg
    426 	 * space to default value.
    427 	 */
    428 	intel_vgpu_init_cfg_space(vgpu, primary);
    429 }
    430