This patch introduces the vGPU configuration space handlers built on the generic MPT framework. In vGPU configuration space emulation, GVT-g will: - Adjust the trapped GPFN(Guest Page Frame Number) of virtual GEN PCI BAR 0, when guest BIOS/OS modify the BAR address. - Emulate OpRegion when guest BIOS configure the OpRegion 3 pages. - Pass-through a part of aperture to guest accodint to the GVT resource allocator. Signed-off-by: Zhi Wang <zhi.a.wang@xxxxxxxxx> --- drivers/gpu/drm/i915/gvt/Makefile | 2 +- drivers/gpu/drm/i915/gvt/cfg_space.c | 177 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/gvt/cfg_space.h | 33 +++++++ drivers/gpu/drm/i915/gvt/gvt.c | 2 + drivers/gpu/drm/i915/gvt/gvt.h | 10 ++ drivers/gpu/drm/i915/gvt/reg.h | 16 ++++ drivers/gpu/drm/i915/gvt/utility.c | 91 ++++++++++++++++++ 7 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/i915/gvt/cfg_space.c create mode 100644 drivers/gpu/drm/i915/gvt/cfg_space.h create mode 100644 drivers/gpu/drm/i915/gvt/utility.c diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile index 360539c..a821d3d 100644 --- a/drivers/gpu/drm/i915/gvt/Makefile +++ b/drivers/gpu/drm/i915/gvt/Makefile @@ -1,5 +1,5 @@ GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \ - trace_points.o interrupt.o gtt.o fb_decoder.o + trace_points.o interrupt.o gtt.o cfg_space.o utility.o fb_decoder.o ccflags-y += -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function i915_gvt-y := $(GVT_SOURCE) diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c new file mode 100644 index 0000000..bda0e9d --- /dev/null +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -0,0 +1,177 @@ +/* + * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "gvt.h" + +static bool cfg_sci_read(struct vgt_device *vgt, unsigned int offset, + void *p_data, int bytes) +{ + gvt_info("[vgt %d] Read SCI Trigger Register, bytes=%d value=0x%x", + vgt->id, bytes, *(u16*)p_data); + + return true; +} + +bool gvt_emulate_cfg_read(struct vgt_device *vgt, unsigned int offset, void *p_data, int bytes) +{ + ASSERT((offset + bytes) <= GVT_CFG_SPACE_SZ); + memcpy(p_data, &vgt->state.cfg.space[offset], bytes); + + /* TODO: hooks */ + offset &= ~3; + switch (offset) { + case 0: + case 4: + break; + case GVT_REG_CFG_SWSCI_TRIGGER: + cfg_sci_read(vgt, offset, p_data, bytes); + break; + default: + break; + } + return true; +} + +bool gvt_emulate_cfg_write(struct vgt_device *vgt, unsigned int off, + void *p_data, int bytes) +{ + char *cfg_space = &vgt->state.cfg.space[0]; + u32 *cfg_reg, new; + u64 size; + u8 old_cmd, cmd_changed; /* we don't care the high 8 bits */ + bool rc = true; + u32 low_mem_max_gpfn; + + ASSERT ((off + bytes) <= GVT_CFG_SPACE_SZ); + cfg_reg = (u32*)(cfg_space + (off & ~3)); + switch (off & ~3) { + case GVT_REG_CFG_VENDOR_ID: + low_mem_max_gpfn = *(u32 *)p_data; + gvt_info("low_mem_max_gpfn: 0x%x", low_mem_max_gpfn); + if (bytes != 4 || + low_mem_max_gpfn >= (1UL << (32-PAGE_SHIFT))) { + gvt_err("invalid low_mem_max_gpfn!"); + break; + } + if (vgt->low_mem_max_gpfn == 0) + vgt->low_mem_max_gpfn = low_mem_max_gpfn; + break; + + case GVT_REG_CFG_COMMAND: + old_cmd = vgt->state.cfg.space[off]; + cmd_changed = old_cmd ^ (*(u8*)p_data); + memcpy (&vgt->state.cfg.space[off], p_data, bytes); + if (cmd_changed & _REGBIT_CFG_COMMAND_MEMORY) { + if (old_cmd & _REGBIT_CFG_COMMAND_MEMORY) { + gvt_hvm_map_aperture(vgt, 0); + } else { + if(!vgt->state.cfg.bar_mapped[1]) { + gvt_hvm_map_aperture(vgt, 1); + gvt_hvm_set_trap_area(vgt, 1); + } + } + } else { + gvt_dbg(GVT_DBG_CORE, "need to trap the PIO BAR? " + "old_cmd=0x%x, cmd_changed=%0x", + old_cmd, cmd_changed); + } + break; + case GVT_REG_CFG_SPACE_BAR0: /* GTTMMIO */ + case GVT_REG_CFG_SPACE_BAR1: /* GMADR */ + case GVT_REG_CFG_SPACE_BAR2: /* IO */ + ASSERT((bytes == 4) && (off & 3) == 0); + new = *(u32 *)p_data; + gvt_info("Programming bar 0x%x with 0x%x", off, new); + size = vgt->state.cfg.bar_size[(off - GVT_REG_CFG_SPACE_BAR0)/8]; + if (new == 0xFFFFFFFF) { + /* + * Power-up software can determine how much address + * space the device requires by writing a value of + * all 1's to the register and then reading the value + * back. The device will return 0's in all don't-care + * address bits. + */ + new = new & ~(size-1); + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1) + gvt_hvm_map_aperture(vgt, 0); + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0) + gvt_hvm_set_trap_area(vgt, 0); + gvt_pci_bar_write_32(vgt, off, new); + } else { + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1) + gvt_hvm_map_aperture(vgt, 0); + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0) + gvt_hvm_set_trap_area(vgt, 0); + gvt_pci_bar_write_32(vgt, off, new); + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1) + gvt_hvm_map_aperture(vgt, 1); + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0) + gvt_hvm_set_trap_area(vgt, 1); + } + break; + + case GVT_REG_CFG_SPACE_MSAC: + gvt_info("Guest write MSAC %x, %d: Not supported yet", + *(char *)p_data, bytes); + break; + + case GVT_REG_CFG_SPACE_BAR1+4: + case GVT_REG_CFG_SPACE_BAR0+4: + case GVT_REG_CFG_SPACE_BAR2+4: + ASSERT((bytes == 4) && (off & 3) == 0); + new = *(u32 *)p_data; + gvt_info("Programming bar 0x%x with 0x%x", off, new); + size = vgt->state.cfg.bar_size[(off - (GVT_REG_CFG_SPACE_BAR0 + 4))/8]; + /* for 32bit mode bar it returns all-0 in upper 32 bit, for 64bit + * mode bar it will calculate the size with lower 32bit and return + * the corresponding value + */ + if (new == 0xFFFFFFFF) { + if (GVT_GET_BITS(*(cfg_space + off - 4), 2, 1) == 2) + new &= ~(size-1) >> 32; + else + new = 0; + *cfg_reg = new; + } else { + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1 + 4) + gvt_hvm_map_aperture(vgt, 0); + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0 + 4) + gvt_hvm_set_trap_area(vgt, 0); + *cfg_reg = new; + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1 + 4) + gvt_hvm_map_aperture(vgt, 1); + if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0 + 4) + gvt_hvm_set_trap_area(vgt, 1); + } + break; + + case 0x90: + case 0x94: + case 0x98: + gvt_info("write to MSI capa(%x) with val (%x)", off, *(u32 *)p_data); + default: + memcpy(&vgt->state.cfg.space[off], p_data, bytes); + break; + } + return rc; +} diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.h b/drivers/gpu/drm/i915/gvt/cfg_space.h new file mode 100644 index 0000000..6d9301b --- /dev/null +++ b/drivers/gpu/drm/i915/gvt/cfg_space.h @@ -0,0 +1,33 @@ +/* + * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __GVT_CFG_SPACE_H__ +#define __GVT_CFG_SPACE_H__ + +bool gvt_emulate_cfg_read(struct vgt_device *vgt, + unsigned int offset, void *p_data, int bytes); + +bool gvt_emulate_cfg_write(struct vgt_device *vgt, + unsigned int offset, void *p_data, int bytes); + +#endif diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 28a51d9..32853b2 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -36,6 +36,8 @@ extern struct gvt_kernel_dm kvmgt_kdm; static struct gvt_io_emulation_ops default_io_emulation_ops = { .emulate_mmio_read = gvt_emulate_mmio_read, .emulate_mmio_write = gvt_emulate_mmio_write, + .emulate_cfg_read = gvt_emulate_cfg_read, + .emulate_cfg_write = gvt_emulate_cfg_write, }; unsigned int pa_to_mmio_offset(struct vgt_device *vgt, diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 83f90a2..244d8764 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -36,6 +36,7 @@ #include "interrupt.h" #include "perf.h" #include "gtt.h" +#include "cfg_space.h" #define GVT_MAX_VGPU 8 @@ -99,6 +100,7 @@ struct gvt_virtual_cfg_state { unsigned char space[GVT_CFG_SPACE_SZ]; bool bar_mapped[GVT_BAR_NUM]; u64 bar_size[GVT_BAR_NUM]; + void *opregion_va; }; struct gvt_virtual_gm_state { @@ -600,6 +602,14 @@ static inline u32 h2g_gtt_index(struct vgt_device *vgt, uint32_t h_index) return (u32)(h2g_gm(vgt, h_addr) >> GTT_PAGE_SHIFT); } +/* get the bits high:low of the data, high and low is starting from zero*/ +#define GVT_GET_BITS(data, high, low) (((data) & ((1 << ((high) + 1)) - 1)) >> (low)) +/* get one bit of the data, bit is starting from zeor */ +#define GVT_GET_BIT(data, bit) GVT_GET_BITS(data, bit, bit) + +int gvt_hvm_map_aperture(struct vgt_device *vgt, int map); +int gvt_hvm_set_trap_area(struct vgt_device *vgt, int map); + #include "mpt.h" #endif diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h index 0e28a71..3fb4495 100644 --- a/drivers/gpu/drm/i915/gvt/reg.h +++ b/drivers/gpu/drm/i915/gvt/reg.h @@ -48,6 +48,22 @@ #define _REGBIT_CFG_SWSCI_SCI_TRIGGER 1 #define GVT_REG_CFG_OPREGION 0xFC +#define GVT_OPREGION_PAGES 2 +#define GVT_OPREGION_PORDER 1 +#define GVT_OPREGION_SIZE (8 * 1024) +#define GVT_OPREGION_REG_CLID 0x1AC +#define GVT_OPREGION_REG_SCIC 0x200 +#define _REGBIT_OPREGION_SCIC_FUNC_MASK 0x1E +#define _REGBIT_OPREGION_SCIC_FUNC_SHIFT 1 +#define _REGBIT_OPREGION_SCIC_SUBFUNC_MASK 0xFF00 +#define _REGBIT_OPREGION_SCIC_SUBFUNC_SHIFT 8 +#define _REGBIT_OPREGION_SCIC_EXIT_MASK 0xE0 +#define GVT_OPREGION_SCIC_F_GETBIOSDATA 4 +#define GVT_OPREGION_SCIC_F_GETBIOSCALLBACKS 6 +#define GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS 0 +#define GVT_OPREGION_SCIC_SF_REQEUSTEDCALLBACKS 1 +#define GVT_OPREGION_REG_PARM 0x204 + #define _REG_GMCH_CONTROL 0x50 #define _REGBIT_BDW_GMCH_GMS_SHIFT 8 #define _REGBIT_BDW_GMCH_GMS_MASK 0xff diff --git a/drivers/gpu/drm/i915/gvt/utility.c b/drivers/gpu/drm/i915/gvt/utility.c new file mode 100644 index 0000000..e5e5183 --- /dev/null +++ b/drivers/gpu/drm/i915/gvt/utility.c @@ -0,0 +1,91 @@ +/* + * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "gvt.h" + +int gvt_hvm_map_aperture(struct vgt_device *vgt, int map) +{ + char *cfg_space = &vgt->state.cfg.space[0]; + uint64_t bar_s; + int r, nr_mfns; + unsigned long first_gfn, first_mfn; + + if (!gvt_pci_mmio_is_enabled(vgt)) + return 0; + + /* guarantee the sequence of map -> unmap -> map -> unmap */ + if (map == vgt->state.cfg.bar_mapped[1]) + return 0; + + cfg_space += GVT_REG_CFG_SPACE_BAR1; /* APERTUR */ + if (GVT_GET_BITS(*cfg_space, 2, 1) == 2){ + /* 64 bits MMIO bar */ + bar_s = * (uint64_t *) cfg_space; + } else { + /* 32 bits MMIO bar */ + bar_s = * (uint32_t*) cfg_space; + } + + first_gfn = (bar_s + gvt_aperture_offset(vgt)) >> PAGE_SHIFT; + first_mfn = gvt_aperture_base(vgt) >> PAGE_SHIFT; + nr_mfns = gvt_aperture_sz(vgt) >> PAGE_SHIFT; + + printk("%s: domid=%d gfn_s=0x%lx mfn_s=0x%lx nr_mfns=0x%x\n", map==0? "remove_map":"add_map", + vgt->vm_id, first_gfn, first_mfn, nr_mfns); + + r = hypervisor_map_mfn_to_gpfn(vgt, first_gfn, first_mfn, + nr_mfns, map, GVT_MAP_APERTURE); + + if (r != 0) + printk(KERN_ERR "gvt_hvm_map_aperture fail with %d!\n", r); + else + vgt->state.cfg.bar_mapped[1] = map; + + return r; +} + +/* + * Zap the GTTMMIO bar area for vGT trap and emulation. + */ +int gvt_hvm_set_trap_area(struct vgt_device *vgt, int map) +{ + char *cfg_space = &vgt->state.cfg.space[0]; + uint64_t bar_s, bar_e; + + if (!gvt_pci_mmio_is_enabled(vgt)) + return 0; + + cfg_space += GVT_REG_CFG_SPACE_BAR0; + if (GVT_GET_BITS(*cfg_space, 2, 1) == 2) { + /* 64 bits MMIO bar */ + bar_s = * (uint64_t *) cfg_space; + } else { + /* 32 bits MMIO bar */ + bar_s = * (uint32_t*) cfg_space; + } + + bar_s &= ~0xF; /* clear the LSB 4 bits */ + bar_e = bar_s + vgt->state.cfg.bar_size[0] - 1; + + return hypervisor_set_trap_area(vgt, bar_s, bar_e, map); +} -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx