Merge tag 'gvt-next-2018-03-08' of https://github.com/intel/gvt-linux into drm-intel-next-queued
gvt-next-2018-03-08 - big refactor for shadow ppgtt (Changbin) - KBL context save/restore via LRI cmd (Weinan) - misc smatch fixes (Zhenyu) - Properly unmap dma for guest page (Changbin) - other misc fixes (Xiong, etc.) Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180308023152.oi4ialn5uxetbruf@zhen-hp.sh.intel.com
This commit is contained in:
commit
ed5c94a85b
@ -3,7 +3,7 @@ GVT_DIR := gvt
|
||||
GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
|
||||
interrupt.o gtt.o cfg_space.o opregion.o mmio.o display.o edid.o \
|
||||
execlist.o scheduler.o sched_policy.o mmio_context.o cmd_parser.o debugfs.o \
|
||||
fb_decoder.o dmabuf.o
|
||||
fb_decoder.o dmabuf.o page_track.o
|
||||
|
||||
ccflags-y += -I$(src) -I$(src)/$(GVT_DIR)
|
||||
i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
|
||||
|
@ -459,7 +459,7 @@ int intel_vgpu_get_dmabuf(struct intel_vgpu *vgpu, unsigned int dmabuf_id)
|
||||
|
||||
obj = vgpu_create_gem(dev, dmabuf_obj->info);
|
||||
if (obj == NULL) {
|
||||
gvt_vgpu_err("create gvt gem obj failed:%d\n", vgpu->id);
|
||||
gvt_vgpu_err("create gvt gem obj failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,6 @@
|
||||
|
||||
struct intel_vgpu_mm;
|
||||
|
||||
#define INTEL_GVT_GTT_HASH_BITS 8
|
||||
#define INTEL_GVT_INVALID_ADDR (~0UL)
|
||||
|
||||
struct intel_gvt_gtt_entry {
|
||||
@ -84,17 +83,12 @@ struct intel_gvt_gtt {
|
||||
void (*mm_free_page_table)(struct intel_vgpu_mm *mm);
|
||||
struct list_head oos_page_use_list_head;
|
||||
struct list_head oos_page_free_list_head;
|
||||
struct list_head mm_lru_list_head;
|
||||
struct list_head ppgtt_mm_lru_list_head;
|
||||
|
||||
struct page *scratch_page;
|
||||
unsigned long scratch_mfn;
|
||||
};
|
||||
|
||||
enum {
|
||||
INTEL_GVT_MM_GGTT = 0,
|
||||
INTEL_GVT_MM_PPGTT,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GTT_TYPE_INVALID = -1,
|
||||
|
||||
@ -125,66 +119,60 @@ typedef enum {
|
||||
GTT_TYPE_MAX,
|
||||
} intel_gvt_gtt_type_t;
|
||||
|
||||
struct intel_vgpu_mm {
|
||||
int type;
|
||||
bool initialized;
|
||||
bool shadowed;
|
||||
|
||||
int page_table_entry_type;
|
||||
u32 page_table_entry_size;
|
||||
u32 page_table_entry_cnt;
|
||||
void *virtual_page_table;
|
||||
void *shadow_page_table;
|
||||
|
||||
int page_table_level;
|
||||
bool has_shadow_page_table;
|
||||
u32 pde_base_index;
|
||||
|
||||
struct list_head list;
|
||||
struct kref ref;
|
||||
atomic_t pincount;
|
||||
struct list_head lru_list;
|
||||
struct intel_vgpu *vgpu;
|
||||
enum intel_gvt_mm_type {
|
||||
INTEL_GVT_MM_GGTT,
|
||||
INTEL_GVT_MM_PPGTT,
|
||||
};
|
||||
|
||||
extern int intel_vgpu_mm_get_entry(
|
||||
struct intel_vgpu_mm *mm,
|
||||
void *page_table, struct intel_gvt_gtt_entry *e,
|
||||
unsigned long index);
|
||||
#define GVT_RING_CTX_NR_PDPS GEN8_3LVL_PDPES
|
||||
|
||||
extern int intel_vgpu_mm_set_entry(
|
||||
struct intel_vgpu_mm *mm,
|
||||
void *page_table, struct intel_gvt_gtt_entry *e,
|
||||
unsigned long index);
|
||||
struct intel_vgpu_mm {
|
||||
enum intel_gvt_mm_type type;
|
||||
struct intel_vgpu *vgpu;
|
||||
|
||||
#define ggtt_get_guest_entry(mm, e, index) \
|
||||
intel_vgpu_mm_get_entry(mm, mm->virtual_page_table, e, index)
|
||||
struct kref ref;
|
||||
atomic_t pincount;
|
||||
|
||||
#define ggtt_set_guest_entry(mm, e, index) \
|
||||
intel_vgpu_mm_set_entry(mm, mm->virtual_page_table, e, index)
|
||||
union {
|
||||
struct {
|
||||
intel_gvt_gtt_type_t root_entry_type;
|
||||
/*
|
||||
* The 4 PDPs in ring context. For 48bit addressing,
|
||||
* only PDP0 is valid and point to PML4. For 32it
|
||||
* addressing, all 4 are used as true PDPs.
|
||||
*/
|
||||
u64 guest_pdps[GVT_RING_CTX_NR_PDPS];
|
||||
u64 shadow_pdps[GVT_RING_CTX_NR_PDPS];
|
||||
bool shadowed;
|
||||
|
||||
#define ggtt_get_shadow_entry(mm, e, index) \
|
||||
intel_vgpu_mm_get_entry(mm, mm->shadow_page_table, e, index)
|
||||
struct list_head list;
|
||||
struct list_head lru_list;
|
||||
} ppgtt_mm;
|
||||
struct {
|
||||
void *virtual_ggtt;
|
||||
} ggtt_mm;
|
||||
};
|
||||
};
|
||||
|
||||
#define ggtt_set_shadow_entry(mm, e, index) \
|
||||
intel_vgpu_mm_set_entry(mm, mm->shadow_page_table, e, index)
|
||||
struct intel_vgpu_mm *intel_vgpu_create_ppgtt_mm(struct intel_vgpu *vgpu,
|
||||
intel_gvt_gtt_type_t root_entry_type, u64 pdps[]);
|
||||
|
||||
#define ppgtt_get_guest_root_entry(mm, e, index) \
|
||||
intel_vgpu_mm_get_entry(mm, mm->virtual_page_table, e, index)
|
||||
static inline void intel_vgpu_mm_get(struct intel_vgpu_mm *mm)
|
||||
{
|
||||
kref_get(&mm->ref);
|
||||
}
|
||||
|
||||
#define ppgtt_set_guest_root_entry(mm, e, index) \
|
||||
intel_vgpu_mm_set_entry(mm, mm->virtual_page_table, e, index)
|
||||
void _intel_vgpu_mm_release(struct kref *mm_ref);
|
||||
|
||||
#define ppgtt_get_shadow_root_entry(mm, e, index) \
|
||||
intel_vgpu_mm_get_entry(mm, mm->shadow_page_table, e, index)
|
||||
static inline void intel_vgpu_mm_put(struct intel_vgpu_mm *mm)
|
||||
{
|
||||
kref_put(&mm->ref, _intel_vgpu_mm_release);
|
||||
}
|
||||
|
||||
#define ppgtt_set_shadow_root_entry(mm, e, index) \
|
||||
intel_vgpu_mm_set_entry(mm, mm->shadow_page_table, e, index)
|
||||
|
||||
extern struct intel_vgpu_mm *intel_vgpu_create_mm(struct intel_vgpu *vgpu,
|
||||
int mm_type, void *virtual_page_table, int page_table_level,
|
||||
u32 pde_base_index);
|
||||
extern void intel_vgpu_destroy_mm(struct kref *mm_ref);
|
||||
static inline void intel_vgpu_destroy_mm(struct intel_vgpu_mm *mm)
|
||||
{
|
||||
intel_vgpu_mm_put(mm);
|
||||
}
|
||||
|
||||
struct intel_vgpu_guest_page;
|
||||
|
||||
@ -196,10 +184,8 @@ struct intel_vgpu_scratch_pt {
|
||||
struct intel_vgpu_gtt {
|
||||
struct intel_vgpu_mm *ggtt_mm;
|
||||
unsigned long active_ppgtt_mm_bitmap;
|
||||
struct list_head mm_list_head;
|
||||
DECLARE_HASHTABLE(shadow_page_hash_table, INTEL_GVT_GTT_HASH_BITS);
|
||||
DECLARE_HASHTABLE(tracked_guest_page_hash_table, INTEL_GVT_GTT_HASH_BITS);
|
||||
atomic_t n_tracked_guest_page;
|
||||
struct list_head ppgtt_mm_list_head;
|
||||
struct radix_tree_root spt_tree;
|
||||
struct list_head oos_page_list_head;
|
||||
struct list_head post_shadow_list_head;
|
||||
struct intel_vgpu_scratch_pt scratch_pt[GTT_TYPE_MAX];
|
||||
@ -216,32 +202,8 @@ extern void intel_gvt_clean_gtt(struct intel_gvt *gvt);
|
||||
extern struct intel_vgpu_mm *intel_gvt_find_ppgtt_mm(struct intel_vgpu *vgpu,
|
||||
int page_table_level, void *root_entry);
|
||||
|
||||
struct intel_vgpu_oos_page;
|
||||
|
||||
struct intel_vgpu_shadow_page {
|
||||
void *vaddr;
|
||||
struct page *page;
|
||||
int type;
|
||||
struct hlist_node node;
|
||||
unsigned long mfn;
|
||||
};
|
||||
|
||||
struct intel_vgpu_page_track {
|
||||
struct hlist_node node;
|
||||
bool tracked;
|
||||
unsigned long gfn;
|
||||
int (*handler)(void *, u64, void *, int);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct intel_vgpu_guest_page {
|
||||
struct intel_vgpu_page_track track;
|
||||
unsigned long write_cnt;
|
||||
struct intel_vgpu_oos_page *oos_page;
|
||||
};
|
||||
|
||||
struct intel_vgpu_oos_page {
|
||||
struct intel_vgpu_guest_page *guest_page;
|
||||
struct intel_vgpu_ppgtt_spt *spt;
|
||||
struct list_head list;
|
||||
struct list_head vm_list;
|
||||
int id;
|
||||
@ -250,42 +212,33 @@ struct intel_vgpu_oos_page {
|
||||
|
||||
#define GTT_ENTRY_NUM_IN_ONE_PAGE 512
|
||||
|
||||
/* Represent a vgpu shadow page table. */
|
||||
struct intel_vgpu_ppgtt_spt {
|
||||
struct intel_vgpu_shadow_page shadow_page;
|
||||
struct intel_vgpu_guest_page guest_page;
|
||||
int guest_page_type;
|
||||
atomic_t refcount;
|
||||
struct intel_vgpu *vgpu;
|
||||
|
||||
struct {
|
||||
intel_gvt_gtt_type_t type;
|
||||
void *vaddr;
|
||||
struct page *page;
|
||||
unsigned long mfn;
|
||||
} shadow_page;
|
||||
|
||||
struct {
|
||||
intel_gvt_gtt_type_t type;
|
||||
unsigned long gfn;
|
||||
unsigned long write_cnt;
|
||||
struct intel_vgpu_oos_page *oos_page;
|
||||
} guest_page;
|
||||
|
||||
DECLARE_BITMAP(post_shadow_bitmap, GTT_ENTRY_NUM_IN_ONE_PAGE);
|
||||
struct list_head post_shadow_list;
|
||||
};
|
||||
|
||||
int intel_vgpu_init_page_track(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_page_track *t,
|
||||
unsigned long gfn,
|
||||
int (*handler)(void *gp, u64, void *, int),
|
||||
void *data);
|
||||
|
||||
void intel_vgpu_clean_page_track(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_page_track *t);
|
||||
|
||||
struct intel_vgpu_page_track *intel_vgpu_find_tracked_page(
|
||||
struct intel_vgpu *vgpu, unsigned long gfn);
|
||||
|
||||
int intel_vgpu_sync_oos_pages(struct intel_vgpu *vgpu);
|
||||
|
||||
int intel_vgpu_flush_post_shadow(struct intel_vgpu *vgpu);
|
||||
|
||||
static inline void intel_gvt_mm_reference(struct intel_vgpu_mm *mm)
|
||||
{
|
||||
kref_get(&mm->ref);
|
||||
}
|
||||
|
||||
static inline void intel_gvt_mm_unreference(struct intel_vgpu_mm *mm)
|
||||
{
|
||||
kref_put(&mm->ref, intel_vgpu_destroy_mm);
|
||||
}
|
||||
|
||||
int intel_vgpu_pin_mm(struct intel_vgpu_mm *mm);
|
||||
|
||||
void intel_vgpu_unpin_mm(struct intel_vgpu_mm *mm);
|
||||
@ -294,21 +247,17 @@ unsigned long intel_vgpu_gma_to_gpa(struct intel_vgpu_mm *mm,
|
||||
unsigned long gma);
|
||||
|
||||
struct intel_vgpu_mm *intel_vgpu_find_ppgtt_mm(struct intel_vgpu *vgpu,
|
||||
int page_table_level, void *root_entry);
|
||||
u64 pdps[]);
|
||||
|
||||
int intel_vgpu_g2v_create_ppgtt_mm(struct intel_vgpu *vgpu,
|
||||
int page_table_level);
|
||||
struct intel_vgpu_mm *intel_vgpu_get_ppgtt_mm(struct intel_vgpu *vgpu,
|
||||
intel_gvt_gtt_type_t root_entry_type, u64 pdps[]);
|
||||
|
||||
int intel_vgpu_g2v_destroy_ppgtt_mm(struct intel_vgpu *vgpu,
|
||||
int page_table_level);
|
||||
int intel_vgpu_put_ppgtt_mm(struct intel_vgpu *vgpu, u64 pdps[]);
|
||||
|
||||
int intel_vgpu_emulate_gtt_mmio_read(struct intel_vgpu *vgpu,
|
||||
int intel_vgpu_emulate_ggtt_mmio_read(struct intel_vgpu *vgpu,
|
||||
unsigned int off, void *p_data, unsigned int bytes);
|
||||
|
||||
int intel_vgpu_emulate_gtt_mmio_write(struct intel_vgpu *vgpu,
|
||||
int intel_vgpu_emulate_ggtt_mmio_write(struct intel_vgpu *vgpu,
|
||||
unsigned int off, void *p_data, unsigned int bytes);
|
||||
|
||||
int intel_vgpu_write_protect_handler(struct intel_vgpu *vgpu, u64 pa,
|
||||
void *p_data, unsigned int bytes);
|
||||
|
||||
#endif /* _GVT_GTT_H_ */
|
||||
|
@ -183,7 +183,7 @@ static const struct intel_gvt_ops intel_gvt_ops = {
|
||||
.get_gvt_attrs = intel_get_gvt_attrs,
|
||||
.vgpu_query_plane = intel_vgpu_query_plane,
|
||||
.vgpu_get_dmabuf = intel_vgpu_get_dmabuf,
|
||||
.write_protect_handler = intel_vgpu_write_protect_handler,
|
||||
.write_protect_handler = intel_vgpu_page_track_handler,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "cmd_parser.h"
|
||||
#include "fb_decoder.h"
|
||||
#include "dmabuf.h"
|
||||
#include "page_track.h"
|
||||
|
||||
#define GVT_MAX_VGPU 8
|
||||
|
||||
@ -131,11 +132,9 @@ struct intel_vgpu_opregion {
|
||||
|
||||
#define vgpu_opregion(vgpu) (&(vgpu->opregion))
|
||||
|
||||
#define INTEL_GVT_MAX_PORT 5
|
||||
|
||||
struct intel_vgpu_display {
|
||||
struct intel_vgpu_i2c_edid i2c_edid;
|
||||
struct intel_vgpu_port ports[INTEL_GVT_MAX_PORT];
|
||||
struct intel_vgpu_port ports[I915_MAX_PORTS];
|
||||
struct intel_vgpu_sbi sbi;
|
||||
};
|
||||
|
||||
@ -190,6 +189,7 @@ struct intel_vgpu {
|
||||
struct intel_vgpu_opregion opregion;
|
||||
struct intel_vgpu_display display;
|
||||
struct intel_vgpu_submission submission;
|
||||
struct radix_tree_root page_track_tree;
|
||||
u32 hws_pga[I915_NUM_ENGINES];
|
||||
|
||||
struct dentry *debugfs;
|
||||
@ -201,8 +201,16 @@ struct intel_vgpu {
|
||||
int num_regions;
|
||||
struct eventfd_ctx *intx_trigger;
|
||||
struct eventfd_ctx *msi_trigger;
|
||||
struct rb_root cache;
|
||||
|
||||
/*
|
||||
* Two caches are used to avoid mapping duplicated pages (eg.
|
||||
* scratch pages). This help to reduce dma setup overhead.
|
||||
*/
|
||||
struct rb_root gfn_cache;
|
||||
struct rb_root dma_addr_cache;
|
||||
unsigned long nr_cache_entries;
|
||||
struct mutex cache_lock;
|
||||
|
||||
struct notifier_block iommu_notifier;
|
||||
struct notifier_block group_notifier;
|
||||
struct kvm *kvm;
|
||||
@ -308,7 +316,10 @@ struct intel_gvt {
|
||||
wait_queue_head_t service_thread_wq;
|
||||
unsigned long service_request;
|
||||
|
||||
struct engine_mmio *engine_mmio_list;
|
||||
struct {
|
||||
struct engine_mmio *mmio;
|
||||
int ctx_mmio_count[I915_NUM_ENGINES];
|
||||
} engine_mmio_list;
|
||||
|
||||
struct dentry *debugfs_root;
|
||||
};
|
||||
|
@ -188,7 +188,9 @@ void enter_failsafe_mode(struct intel_vgpu *vgpu, int reason)
|
||||
static int sanitize_fence_mmio_access(struct intel_vgpu *vgpu,
|
||||
unsigned int fence_num, void *p_data, unsigned int bytes)
|
||||
{
|
||||
if (fence_num >= vgpu_fence_sz(vgpu)) {
|
||||
unsigned int max_fence = vgpu_fence_sz(vgpu);
|
||||
|
||||
if (fence_num >= max_fence) {
|
||||
|
||||
/* When guest access oob fence regs without access
|
||||
* pv_info first, we treat guest not supporting GVT,
|
||||
@ -201,7 +203,7 @@ static int sanitize_fence_mmio_access(struct intel_vgpu *vgpu,
|
||||
if (!vgpu->mmio.disable_warn_untrack) {
|
||||
gvt_vgpu_err("found oob fence register access\n");
|
||||
gvt_vgpu_err("total fence %d, access fence %d\n",
|
||||
vgpu_fence_sz(vgpu), fence_num);
|
||||
max_fence, fence_num);
|
||||
}
|
||||
memset(p_data, 0, bytes);
|
||||
return -EINVAL;
|
||||
@ -320,7 +322,7 @@ static int gdrst_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
intel_gvt_reset_vgpu_locked(vgpu, false, engine_mask);
|
||||
|
||||
/* sw will wait for the device to ack the reset request */
|
||||
vgpu_vreg(vgpu, offset) = 0;
|
||||
vgpu_vreg(vgpu, offset) = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1139,21 +1141,21 @@ static int pvinfo_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
|
||||
static int handle_g2v_notification(struct intel_vgpu *vgpu, int notification)
|
||||
{
|
||||
int ret = 0;
|
||||
intel_gvt_gtt_type_t root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
|
||||
struct intel_vgpu_mm *mm;
|
||||
u64 *pdps;
|
||||
|
||||
pdps = (u64 *)&vgpu_vreg64_t(vgpu, vgtif_reg(pdp[0]));
|
||||
|
||||
switch (notification) {
|
||||
case VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE:
|
||||
ret = intel_vgpu_g2v_create_ppgtt_mm(vgpu, 3);
|
||||
break;
|
||||
case VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY:
|
||||
ret = intel_vgpu_g2v_destroy_ppgtt_mm(vgpu, 3);
|
||||
break;
|
||||
root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
|
||||
case VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE:
|
||||
ret = intel_vgpu_g2v_create_ppgtt_mm(vgpu, 4);
|
||||
break;
|
||||
mm = intel_vgpu_get_ppgtt_mm(vgpu, root_entry_type, pdps);
|
||||
return PTR_ERR_OR_ZERO(mm);
|
||||
case VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY:
|
||||
case VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY:
|
||||
ret = intel_vgpu_g2v_destroy_ppgtt_mm(vgpu, 4);
|
||||
break;
|
||||
return intel_vgpu_put_ppgtt_mm(vgpu, pdps);
|
||||
case VGT_G2V_EXECLIST_CONTEXT_CREATE:
|
||||
case VGT_G2V_EXECLIST_CONTEXT_DESTROY:
|
||||
case 1: /* Remove this in guest driver. */
|
||||
@ -1161,7 +1163,7 @@ static int handle_g2v_notification(struct intel_vgpu *vgpu, int notification)
|
||||
default:
|
||||
gvt_vgpu_err("Invalid PV notification %d\n", notification);
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_display_ready_uevent(struct intel_vgpu *vgpu, int ready)
|
||||
@ -1389,8 +1391,8 @@ static int hws_pga_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
int ring_id = intel_gvt_render_mmio_to_ring_id(vgpu->gvt, offset);
|
||||
|
||||
if (!intel_gvt_ggtt_validate_range(vgpu, value, I915_GTT_PAGE_SIZE)) {
|
||||
gvt_vgpu_err("VM(%d) write invalid HWSP address, reg:0x%x, value:0x%x\n",
|
||||
vgpu->id, offset, value);
|
||||
gvt_vgpu_err("write invalid HWSP address, reg:0x%x, value:0x%x\n",
|
||||
offset, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
@ -1399,8 +1401,8 @@ static int hws_pga_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
* support BDW, SKL or other platforms with same HWSP registers.
|
||||
*/
|
||||
if (unlikely(ring_id < 0 || ring_id >= I915_NUM_ENGINES)) {
|
||||
gvt_vgpu_err("VM(%d) access unknown hardware status page register:0x%x\n",
|
||||
vgpu->id, offset);
|
||||
gvt_vgpu_err("access unknown hardware status page register:0x%x\n",
|
||||
offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
vgpu->hws_pga[ring_id] = value;
|
||||
|
@ -44,13 +44,18 @@ struct intel_gvt_mpt {
|
||||
void (*detach_vgpu)(unsigned long handle);
|
||||
int (*inject_msi)(unsigned long handle, u32 addr, u16 data);
|
||||
unsigned long (*from_virt_to_mfn)(void *p);
|
||||
int (*set_wp_page)(unsigned long handle, u64 gfn);
|
||||
int (*unset_wp_page)(unsigned long handle, u64 gfn);
|
||||
int (*enable_page_track)(unsigned long handle, u64 gfn);
|
||||
int (*disable_page_track)(unsigned long handle, u64 gfn);
|
||||
int (*read_gpa)(unsigned long handle, unsigned long gpa, void *buf,
|
||||
unsigned long len);
|
||||
int (*write_gpa)(unsigned long handle, unsigned long gpa, void *buf,
|
||||
unsigned long len);
|
||||
unsigned long (*gfn_to_mfn)(unsigned long handle, unsigned long gfn);
|
||||
|
||||
int (*dma_map_guest_page)(unsigned long handle, unsigned long gfn,
|
||||
dma_addr_t *dma_addr);
|
||||
void (*dma_unmap_guest_page)(unsigned long handle, dma_addr_t dma_addr);
|
||||
|
||||
int (*map_gfn_to_mfn)(unsigned long handle, unsigned long gfn,
|
||||
unsigned long mfn, unsigned int nr, bool map);
|
||||
int (*set_trap_area)(unsigned long handle, u64 start, u64 end,
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/vfio.h>
|
||||
#include <linux/mdev.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "gvt.h"
|
||||
@ -84,12 +85,16 @@ struct kvmgt_guest_info {
|
||||
#define NR_BKT (1 << 18)
|
||||
struct hlist_head ptable[NR_BKT];
|
||||
#undef NR_BKT
|
||||
struct dentry *debugfs_cache_entries;
|
||||
};
|
||||
|
||||
struct gvt_dma {
|
||||
struct rb_node node;
|
||||
struct intel_vgpu *vgpu;
|
||||
struct rb_node gfn_node;
|
||||
struct rb_node dma_addr_node;
|
||||
gfn_t gfn;
|
||||
unsigned long iova;
|
||||
dma_addr_t dma_addr;
|
||||
struct kref ref;
|
||||
};
|
||||
|
||||
static inline bool handle_valid(unsigned long handle)
|
||||
@ -101,165 +106,167 @@ static int kvmgt_guest_init(struct mdev_device *mdev);
|
||||
static void intel_vgpu_release_work(struct work_struct *work);
|
||||
static bool kvmgt_guest_exit(struct kvmgt_guest_info *info);
|
||||
|
||||
static int gvt_dma_map_iova(struct intel_vgpu *vgpu, kvm_pfn_t pfn,
|
||||
unsigned long *iova)
|
||||
static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
||||
dma_addr_t *dma_addr)
|
||||
{
|
||||
struct page *page;
|
||||
struct device *dev = &vgpu->gvt->dev_priv->drm.pdev->dev;
|
||||
dma_addr_t daddr;
|
||||
struct page *page;
|
||||
unsigned long pfn;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!pfn_valid(pfn)))
|
||||
return -EFAULT;
|
||||
/* Pin the page first. */
|
||||
ret = vfio_pin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1,
|
||||
IOMMU_READ | IOMMU_WRITE, &pfn);
|
||||
if (ret != 1) {
|
||||
gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx: %d\n",
|
||||
gfn, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Setup DMA mapping. */
|
||||
page = pfn_to_page(pfn);
|
||||
daddr = dma_map_page(dev, page, 0, PAGE_SIZE,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(dev, daddr))
|
||||
*dma_addr = dma_map_page(dev, page, 0, PAGE_SIZE,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(dev, *dma_addr)) {
|
||||
gvt_vgpu_err("DMA mapping failed for gfn 0x%lx\n", gfn);
|
||||
vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*iova = (unsigned long)(daddr >> PAGE_SHIFT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gvt_dma_unmap_iova(struct intel_vgpu *vgpu, unsigned long iova)
|
||||
static void gvt_dma_unmap_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
||||
dma_addr_t dma_addr)
|
||||
{
|
||||
struct device *dev = &vgpu->gvt->dev_priv->drm.pdev->dev;
|
||||
dma_addr_t daddr;
|
||||
int ret;
|
||||
|
||||
daddr = (dma_addr_t)(iova << PAGE_SHIFT);
|
||||
dma_unmap_page(dev, daddr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
||||
dma_unmap_page(dev, dma_addr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
||||
ret = vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1);
|
||||
WARN_ON(ret != 1);
|
||||
}
|
||||
|
||||
static struct gvt_dma *__gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn)
|
||||
static struct gvt_dma *__gvt_cache_find_dma_addr(struct intel_vgpu *vgpu,
|
||||
dma_addr_t dma_addr)
|
||||
{
|
||||
struct rb_node *node = vgpu->vdev.cache.rb_node;
|
||||
struct gvt_dma *ret = NULL;
|
||||
struct rb_node *node = vgpu->vdev.dma_addr_cache.rb_node;
|
||||
struct gvt_dma *itr;
|
||||
|
||||
while (node) {
|
||||
struct gvt_dma *itr = rb_entry(node, struct gvt_dma, node);
|
||||
itr = rb_entry(node, struct gvt_dma, dma_addr_node);
|
||||
|
||||
if (dma_addr < itr->dma_addr)
|
||||
node = node->rb_left;
|
||||
else if (dma_addr > itr->dma_addr)
|
||||
node = node->rb_right;
|
||||
else
|
||||
return itr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct gvt_dma *__gvt_cache_find_gfn(struct intel_vgpu *vgpu, gfn_t gfn)
|
||||
{
|
||||
struct rb_node *node = vgpu->vdev.gfn_cache.rb_node;
|
||||
struct gvt_dma *itr;
|
||||
|
||||
while (node) {
|
||||
itr = rb_entry(node, struct gvt_dma, gfn_node);
|
||||
|
||||
if (gfn < itr->gfn)
|
||||
node = node->rb_left;
|
||||
else if (gfn > itr->gfn)
|
||||
node = node->rb_right;
|
||||
else {
|
||||
ret = itr;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
return itr;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned long gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn)
|
||||
{
|
||||
struct gvt_dma *entry;
|
||||
unsigned long iova;
|
||||
|
||||
mutex_lock(&vgpu->vdev.cache_lock);
|
||||
|
||||
entry = __gvt_cache_find(vgpu, gfn);
|
||||
iova = (entry == NULL) ? INTEL_GVT_INVALID_ADDR : entry->iova;
|
||||
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
return iova;
|
||||
}
|
||||
|
||||
static void gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn,
|
||||
unsigned long iova)
|
||||
static void __gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn,
|
||||
dma_addr_t dma_addr)
|
||||
{
|
||||
struct gvt_dma *new, *itr;
|
||||
struct rb_node **link = &vgpu->vdev.cache.rb_node, *parent = NULL;
|
||||
struct rb_node **link, *parent = NULL;
|
||||
|
||||
new = kzalloc(sizeof(struct gvt_dma), GFP_KERNEL);
|
||||
if (!new)
|
||||
return;
|
||||
|
||||
new->vgpu = vgpu;
|
||||
new->gfn = gfn;
|
||||
new->iova = iova;
|
||||
new->dma_addr = dma_addr;
|
||||
kref_init(&new->ref);
|
||||
|
||||
mutex_lock(&vgpu->vdev.cache_lock);
|
||||
/* gfn_cache maps gfn to struct gvt_dma. */
|
||||
link = &vgpu->vdev.gfn_cache.rb_node;
|
||||
while (*link) {
|
||||
parent = *link;
|
||||
itr = rb_entry(parent, struct gvt_dma, node);
|
||||
itr = rb_entry(parent, struct gvt_dma, gfn_node);
|
||||
|
||||
if (gfn == itr->gfn)
|
||||
goto out;
|
||||
else if (gfn < itr->gfn)
|
||||
if (gfn < itr->gfn)
|
||||
link = &parent->rb_left;
|
||||
else
|
||||
link = &parent->rb_right;
|
||||
}
|
||||
rb_link_node(&new->gfn_node, parent, link);
|
||||
rb_insert_color(&new->gfn_node, &vgpu->vdev.gfn_cache);
|
||||
|
||||
rb_link_node(&new->node, parent, link);
|
||||
rb_insert_color(&new->node, &vgpu->vdev.cache);
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
return;
|
||||
/* dma_addr_cache maps dma addr to struct gvt_dma. */
|
||||
parent = NULL;
|
||||
link = &vgpu->vdev.dma_addr_cache.rb_node;
|
||||
while (*link) {
|
||||
parent = *link;
|
||||
itr = rb_entry(parent, struct gvt_dma, dma_addr_node);
|
||||
|
||||
out:
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
kfree(new);
|
||||
if (dma_addr < itr->dma_addr)
|
||||
link = &parent->rb_left;
|
||||
else
|
||||
link = &parent->rb_right;
|
||||
}
|
||||
rb_link_node(&new->dma_addr_node, parent, link);
|
||||
rb_insert_color(&new->dma_addr_node, &vgpu->vdev.dma_addr_cache);
|
||||
|
||||
vgpu->vdev.nr_cache_entries++;
|
||||
}
|
||||
|
||||
static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu,
|
||||
struct gvt_dma *entry)
|
||||
{
|
||||
rb_erase(&entry->node, &vgpu->vdev.cache);
|
||||
rb_erase(&entry->gfn_node, &vgpu->vdev.gfn_cache);
|
||||
rb_erase(&entry->dma_addr_node, &vgpu->vdev.dma_addr_cache);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn)
|
||||
{
|
||||
struct device *dev = mdev_dev(vgpu->vdev.mdev);
|
||||
struct gvt_dma *this;
|
||||
unsigned long g1;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&vgpu->vdev.cache_lock);
|
||||
this = __gvt_cache_find(vgpu, gfn);
|
||||
if (!this) {
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
g1 = gfn;
|
||||
gvt_dma_unmap_iova(vgpu, this->iova);
|
||||
rc = vfio_unpin_pages(dev, &g1, 1);
|
||||
WARN_ON(rc != 1);
|
||||
__gvt_cache_remove_entry(vgpu, this);
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
}
|
||||
|
||||
static void gvt_cache_init(struct intel_vgpu *vgpu)
|
||||
{
|
||||
vgpu->vdev.cache = RB_ROOT;
|
||||
mutex_init(&vgpu->vdev.cache_lock);
|
||||
vgpu->vdev.nr_cache_entries--;
|
||||
}
|
||||
|
||||
static void gvt_cache_destroy(struct intel_vgpu *vgpu)
|
||||
{
|
||||
struct gvt_dma *dma;
|
||||
struct rb_node *node = NULL;
|
||||
struct device *dev = mdev_dev(vgpu->vdev.mdev);
|
||||
unsigned long gfn;
|
||||
|
||||
for (;;) {
|
||||
mutex_lock(&vgpu->vdev.cache_lock);
|
||||
node = rb_first(&vgpu->vdev.cache);
|
||||
node = rb_first(&vgpu->vdev.gfn_cache);
|
||||
if (!node) {
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
break;
|
||||
}
|
||||
dma = rb_entry(node, struct gvt_dma, node);
|
||||
gvt_dma_unmap_iova(vgpu, dma->iova);
|
||||
gfn = dma->gfn;
|
||||
dma = rb_entry(node, struct gvt_dma, gfn_node);
|
||||
gvt_dma_unmap_page(vgpu, dma->gfn, dma->dma_addr);
|
||||
__gvt_cache_remove_entry(vgpu, dma);
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
vfio_unpin_pages(dev, &gfn, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void gvt_cache_init(struct intel_vgpu *vgpu)
|
||||
{
|
||||
vgpu->vdev.gfn_cache = RB_ROOT;
|
||||
vgpu->vdev.dma_addr_cache = RB_ROOT;
|
||||
vgpu->vdev.nr_cache_entries = 0;
|
||||
mutex_init(&vgpu->vdev.cache_lock);
|
||||
}
|
||||
|
||||
static void kvmgt_protect_table_init(struct kvmgt_guest_info *info)
|
||||
{
|
||||
hash_init(info->ptable);
|
||||
@ -452,7 +459,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
|
||||
vgpu = intel_gvt_ops->vgpu_create(gvt, type);
|
||||
if (IS_ERR_OR_NULL(vgpu)) {
|
||||
ret = vgpu == NULL ? -EFAULT : PTR_ERR(vgpu);
|
||||
gvt_vgpu_err("failed to create intel vgpu: %d\n", ret);
|
||||
gvt_err("failed to create intel vgpu: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -489,13 +496,22 @@ static int intel_vgpu_iommu_notifier(struct notifier_block *nb,
|
||||
|
||||
if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
|
||||
struct vfio_iommu_type1_dma_unmap *unmap = data;
|
||||
unsigned long gfn, end_gfn;
|
||||
struct gvt_dma *entry;
|
||||
unsigned long iov_pfn, end_iov_pfn;
|
||||
|
||||
gfn = unmap->iova >> PAGE_SHIFT;
|
||||
end_gfn = gfn + unmap->size / PAGE_SIZE;
|
||||
iov_pfn = unmap->iova >> PAGE_SHIFT;
|
||||
end_iov_pfn = iov_pfn + unmap->size / PAGE_SIZE;
|
||||
|
||||
while (gfn < end_gfn)
|
||||
gvt_cache_remove(vgpu, gfn++);
|
||||
mutex_lock(&vgpu->vdev.cache_lock);
|
||||
for (; iov_pfn < end_iov_pfn; iov_pfn++) {
|
||||
entry = __gvt_cache_find_gfn(vgpu, iov_pfn);
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr);
|
||||
__gvt_cache_remove_entry(vgpu, entry);
|
||||
}
|
||||
mutex_unlock(&vgpu->vdev.cache_lock);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
@ -1321,7 +1337,7 @@ static void kvmgt_host_exit(struct device *dev, void *gvt)
|
||||
mdev_unregister_device(dev);
|
||||
}
|
||||
|
||||
static int kvmgt_write_protect_add(unsigned long handle, u64 gfn)
|
||||
static int kvmgt_page_track_add(unsigned long handle, u64 gfn)
|
||||
{
|
||||
struct kvmgt_guest_info *info;
|
||||
struct kvm *kvm;
|
||||
@ -1355,7 +1371,7 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn)
|
||||
static int kvmgt_page_track_remove(unsigned long handle, u64 gfn)
|
||||
{
|
||||
struct kvmgt_guest_info *info;
|
||||
struct kvm *kvm;
|
||||
@ -1483,11 +1499,20 @@ static int kvmgt_guest_init(struct mdev_device *mdev)
|
||||
info->track_node.track_flush_slot = kvmgt_page_track_flush_slot;
|
||||
kvm_page_track_register_notifier(kvm, &info->track_node);
|
||||
|
||||
info->debugfs_cache_entries = debugfs_create_ulong(
|
||||
"kvmgt_nr_cache_entries",
|
||||
0444, vgpu->debugfs,
|
||||
&vgpu->vdev.nr_cache_entries);
|
||||
if (!info->debugfs_cache_entries)
|
||||
gvt_vgpu_err("Cannot create kvmgt debugfs entry\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool kvmgt_guest_exit(struct kvmgt_guest_info *info)
|
||||
{
|
||||
debugfs_remove(info->debugfs_cache_entries);
|
||||
|
||||
kvm_page_track_unregister_notifier(info->kvm, &info->track_node);
|
||||
kvm_put_kvm(info->kvm);
|
||||
kvmgt_protect_table_destroy(info);
|
||||
@ -1527,39 +1552,77 @@ static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data)
|
||||
|
||||
static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn)
|
||||
{
|
||||
unsigned long iova, pfn;
|
||||
struct kvmgt_guest_info *info;
|
||||
struct device *dev;
|
||||
struct intel_vgpu *vgpu;
|
||||
int rc;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
if (!handle_valid(handle))
|
||||
return INTEL_GVT_INVALID_ADDR;
|
||||
|
||||
info = (struct kvmgt_guest_info *)handle;
|
||||
|
||||
pfn = gfn_to_pfn(info->kvm, gfn);
|
||||
if (is_error_noslot_pfn(pfn))
|
||||
return INTEL_GVT_INVALID_ADDR;
|
||||
|
||||
return pfn;
|
||||
}
|
||||
|
||||
int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn,
|
||||
dma_addr_t *dma_addr)
|
||||
{
|
||||
struct kvmgt_guest_info *info;
|
||||
struct intel_vgpu *vgpu;
|
||||
struct gvt_dma *entry;
|
||||
int ret;
|
||||
|
||||
if (!handle_valid(handle))
|
||||
return -EINVAL;
|
||||
|
||||
info = (struct kvmgt_guest_info *)handle;
|
||||
vgpu = info->vgpu;
|
||||
iova = gvt_cache_find(info->vgpu, gfn);
|
||||
if (iova != INTEL_GVT_INVALID_ADDR)
|
||||
return iova;
|
||||
|
||||
pfn = INTEL_GVT_INVALID_ADDR;
|
||||
dev = mdev_dev(info->vgpu->vdev.mdev);
|
||||
rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn);
|
||||
if (rc != 1) {
|
||||
gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx: %d\n",
|
||||
gfn, rc);
|
||||
return INTEL_GVT_INVALID_ADDR;
|
||||
}
|
||||
/* transfer to host iova for GFX to use DMA */
|
||||
rc = gvt_dma_map_iova(info->vgpu, pfn, &iova);
|
||||
if (rc) {
|
||||
gvt_vgpu_err("gvt_dma_map_iova failed for gfn: 0x%lx\n", gfn);
|
||||
vfio_unpin_pages(dev, &gfn, 1);
|
||||
return INTEL_GVT_INVALID_ADDR;
|
||||
mutex_lock(&info->vgpu->vdev.cache_lock);
|
||||
|
||||
entry = __gvt_cache_find_gfn(info->vgpu, gfn);
|
||||
if (!entry) {
|
||||
ret = gvt_dma_map_page(vgpu, gfn, dma_addr);
|
||||
if (ret) {
|
||||
mutex_unlock(&info->vgpu->vdev.cache_lock);
|
||||
return ret;
|
||||
}
|
||||
__gvt_cache_add(info->vgpu, gfn, *dma_addr);
|
||||
} else {
|
||||
kref_get(&entry->ref);
|
||||
*dma_addr = entry->dma_addr;
|
||||
}
|
||||
|
||||
gvt_cache_add(info->vgpu, gfn, iova);
|
||||
return iova;
|
||||
mutex_unlock(&info->vgpu->vdev.cache_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __gvt_dma_release(struct kref *ref)
|
||||
{
|
||||
struct gvt_dma *entry = container_of(ref, typeof(*entry), ref);
|
||||
|
||||
gvt_dma_unmap_page(entry->vgpu, entry->gfn, entry->dma_addr);
|
||||
__gvt_cache_remove_entry(entry->vgpu, entry);
|
||||
}
|
||||
|
||||
void kvmgt_dma_unmap_guest_page(unsigned long handle, dma_addr_t dma_addr)
|
||||
{
|
||||
struct kvmgt_guest_info *info;
|
||||
struct gvt_dma *entry;
|
||||
|
||||
if (!handle_valid(handle))
|
||||
return;
|
||||
|
||||
info = (struct kvmgt_guest_info *)handle;
|
||||
|
||||
mutex_lock(&info->vgpu->vdev.cache_lock);
|
||||
entry = __gvt_cache_find_dma_addr(info->vgpu, dma_addr);
|
||||
if (entry)
|
||||
kref_put(&entry->ref, __gvt_dma_release);
|
||||
mutex_unlock(&info->vgpu->vdev.cache_lock);
|
||||
}
|
||||
|
||||
static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
|
||||
@ -1629,11 +1692,13 @@ struct intel_gvt_mpt kvmgt_mpt = {
|
||||
.detach_vgpu = kvmgt_detach_vgpu,
|
||||
.inject_msi = kvmgt_inject_msi,
|
||||
.from_virt_to_mfn = kvmgt_virt_to_pfn,
|
||||
.set_wp_page = kvmgt_write_protect_add,
|
||||
.unset_wp_page = kvmgt_write_protect_remove,
|
||||
.enable_page_track = kvmgt_page_track_add,
|
||||
.disable_page_track = kvmgt_page_track_remove,
|
||||
.read_gpa = kvmgt_read_gpa,
|
||||
.write_gpa = kvmgt_write_gpa,
|
||||
.gfn_to_mfn = kvmgt_gfn_to_pfn,
|
||||
.dma_map_guest_page = kvmgt_dma_map_guest_page,
|
||||
.dma_unmap_guest_page = kvmgt_dma_unmap_guest_page,
|
||||
.set_opregion = kvmgt_set_opregion,
|
||||
.get_vfio_device = kvmgt_get_vfio_device,
|
||||
.put_vfio_device = kvmgt_put_vfio_device,
|
||||
|
@ -76,10 +76,9 @@ static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, uint64_t pa,
|
||||
else
|
||||
intel_vgpu_default_mmio_write(vgpu, offset, p_data,
|
||||
bytes);
|
||||
} else if (reg_is_gtt(gvt, offset) &&
|
||||
vgpu->gtt.ggtt_mm->virtual_page_table) {
|
||||
} else if (reg_is_gtt(gvt, offset)) {
|
||||
offset -= gvt->device_info.gtt_start_offset;
|
||||
pt = vgpu->gtt.ggtt_mm->virtual_page_table + offset;
|
||||
pt = vgpu->gtt.ggtt_mm->ggtt_mm.virtual_ggtt + offset;
|
||||
if (read)
|
||||
memcpy(p_data, pt, bytes);
|
||||
else
|
||||
@ -125,7 +124,7 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa,
|
||||
if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1)))
|
||||
goto err;
|
||||
|
||||
ret = intel_vgpu_emulate_gtt_mmio_read(vgpu, offset,
|
||||
ret = intel_vgpu_emulate_ggtt_mmio_read(vgpu, offset,
|
||||
p_data, bytes);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -198,7 +197,7 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa,
|
||||
if (WARN_ON(!reg_is_gtt(gvt, offset + bytes - 1)))
|
||||
goto err;
|
||||
|
||||
ret = intel_vgpu_emulate_gtt_mmio_write(vgpu, offset,
|
||||
ret = intel_vgpu_emulate_ggtt_mmio_write(vgpu, offset,
|
||||
p_data, bytes);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
@ -50,6 +50,8 @@
|
||||
#define RING_GFX_MODE(base) _MMIO((base) + 0x29c)
|
||||
#define VF_GUARDBAND _MMIO(0x83a4)
|
||||
|
||||
#define GEN9_MOCS_SIZE 64
|
||||
|
||||
/* Raw offset is appened to each line for convenience. */
|
||||
static struct engine_mmio gen8_engine_mmio_list[] __cacheline_aligned = {
|
||||
{RCS, GFX_MODE_GEN7, 0xffff, false}, /* 0x229c */
|
||||
@ -151,8 +153,8 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = {
|
||||
|
||||
static struct {
|
||||
bool initialized;
|
||||
u32 control_table[I915_NUM_ENGINES][64];
|
||||
u32 l3cc_table[32];
|
||||
u32 control_table[I915_NUM_ENGINES][GEN9_MOCS_SIZE];
|
||||
u32 l3cc_table[GEN9_MOCS_SIZE / 2];
|
||||
} gen9_render_mocs;
|
||||
|
||||
static void load_render_mocs(struct drm_i915_private *dev_priv)
|
||||
@ -169,7 +171,7 @@ static void load_render_mocs(struct drm_i915_private *dev_priv)
|
||||
|
||||
for (ring_id = 0; ring_id < ARRAY_SIZE(regs); ring_id++) {
|
||||
offset.reg = regs[ring_id];
|
||||
for (i = 0; i < 64; i++) {
|
||||
for (i = 0; i < GEN9_MOCS_SIZE; i++) {
|
||||
gen9_render_mocs.control_table[ring_id][i] =
|
||||
I915_READ_FW(offset);
|
||||
offset.reg += 4;
|
||||
@ -177,7 +179,7 @@ static void load_render_mocs(struct drm_i915_private *dev_priv)
|
||||
}
|
||||
|
||||
offset.reg = 0xb020;
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (i = 0; i < GEN9_MOCS_SIZE / 2; i++) {
|
||||
gen9_render_mocs.l3cc_table[i] =
|
||||
I915_READ_FW(offset);
|
||||
offset.reg += 4;
|
||||
@ -185,6 +187,153 @@ static void load_render_mocs(struct drm_i915_private *dev_priv)
|
||||
gen9_render_mocs.initialized = true;
|
||||
}
|
||||
|
||||
static int
|
||||
restore_context_mmio_for_inhibit(struct intel_vgpu *vgpu,
|
||||
struct i915_request *req)
|
||||
{
|
||||
u32 *cs;
|
||||
int ret;
|
||||
struct engine_mmio *mmio;
|
||||
struct intel_gvt *gvt = vgpu->gvt;
|
||||
int ring_id = req->engine->id;
|
||||
int count = gvt->engine_mmio_list.ctx_mmio_count[ring_id];
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
ret = req->engine->emit_flush(req, EMIT_BARRIER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cs = intel_ring_begin(req, count * 2 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(count);
|
||||
for (mmio = gvt->engine_mmio_list.mmio;
|
||||
i915_mmio_reg_valid(mmio->reg); mmio++) {
|
||||
if (mmio->ring_id != ring_id ||
|
||||
!mmio->in_context)
|
||||
continue;
|
||||
|
||||
*cs++ = i915_mmio_reg_offset(mmio->reg);
|
||||
*cs++ = vgpu_vreg_t(vgpu, mmio->reg) |
|
||||
(mmio->mask << 16);
|
||||
gvt_dbg_core("add lri reg pair 0x%x:0x%x in inhibit ctx, vgpu:%d, rind_id:%d\n",
|
||||
*(cs-2), *(cs-1), vgpu->id, ring_id);
|
||||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
|
||||
ret = req->engine->emit_flush(req, EMIT_BARRIER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
restore_render_mocs_control_for_inhibit(struct intel_vgpu *vgpu,
|
||||
struct i915_request *req)
|
||||
{
|
||||
unsigned int index;
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2 * GEN9_MOCS_SIZE + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(GEN9_MOCS_SIZE);
|
||||
|
||||
for (index = 0; index < GEN9_MOCS_SIZE; index++) {
|
||||
*cs++ = i915_mmio_reg_offset(GEN9_GFX_MOCS(index));
|
||||
*cs++ = vgpu_vreg_t(vgpu, GEN9_GFX_MOCS(index));
|
||||
gvt_dbg_core("add lri reg pair 0x%x:0x%x in inhibit ctx, vgpu:%d, rind_id:%d\n",
|
||||
*(cs-2), *(cs-1), vgpu->id, req->engine->id);
|
||||
|
||||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
restore_render_mocs_l3cc_for_inhibit(struct intel_vgpu *vgpu,
|
||||
struct i915_request *req)
|
||||
{
|
||||
unsigned int index;
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2 * GEN9_MOCS_SIZE / 2 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(GEN9_MOCS_SIZE / 2);
|
||||
|
||||
for (index = 0; index < GEN9_MOCS_SIZE / 2; index++) {
|
||||
*cs++ = i915_mmio_reg_offset(GEN9_LNCFCMOCS(index));
|
||||
*cs++ = vgpu_vreg_t(vgpu, GEN9_LNCFCMOCS(index));
|
||||
gvt_dbg_core("add lri reg pair 0x%x:0x%x in inhibit ctx, vgpu:%d, rind_id:%d\n",
|
||||
*(cs-2), *(cs-1), vgpu->id, req->engine->id);
|
||||
|
||||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use lri command to initialize the mmio which is in context state image for
|
||||
* inhibit context, it contains tracked engine mmio, render_mocs and
|
||||
* render_mocs_l3cc.
|
||||
*/
|
||||
int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu,
|
||||
struct i915_request *req)
|
||||
{
|
||||
int ret;
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
|
||||
ret = restore_context_mmio_for_inhibit(vgpu, req);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* no MOCS register in context except render engine */
|
||||
if (req->engine->id != RCS)
|
||||
goto out;
|
||||
|
||||
ret = restore_render_mocs_control_for_inhibit(vgpu, req);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = restore_render_mocs_l3cc_for_inhibit(vgpu, req);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
cs = intel_ring_begin(req, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handle_tlb_pending_event(struct intel_vgpu *vgpu, int ring_id)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
|
||||
@ -251,11 +400,14 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next,
|
||||
if (WARN_ON(ring_id >= ARRAY_SIZE(regs)))
|
||||
return;
|
||||
|
||||
if (IS_KABYLAKE(dev_priv) && ring_id == RCS)
|
||||
return;
|
||||
|
||||
if (!pre && !gen9_render_mocs.initialized)
|
||||
load_render_mocs(dev_priv);
|
||||
|
||||
offset.reg = regs[ring_id];
|
||||
for (i = 0; i < 64; i++) {
|
||||
for (i = 0; i < GEN9_MOCS_SIZE; i++) {
|
||||
if (pre)
|
||||
old_v = vgpu_vreg_t(pre, offset);
|
||||
else
|
||||
@ -273,7 +425,7 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next,
|
||||
|
||||
if (ring_id == RCS) {
|
||||
l3_offset.reg = 0xb020;
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (i = 0; i < GEN9_MOCS_SIZE / 2; i++) {
|
||||
if (pre)
|
||||
old_v = vgpu_vreg_t(pre, l3_offset);
|
||||
else
|
||||
@ -293,6 +445,16 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next,
|
||||
|
||||
#define CTX_CONTEXT_CONTROL_VAL 0x03
|
||||
|
||||
bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id)
|
||||
{
|
||||
u32 *reg_state = ctx->engine[ring_id].lrc_reg_state;
|
||||
u32 inhibit_mask =
|
||||
_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
|
||||
|
||||
return inhibit_mask ==
|
||||
(reg_state[CTX_CONTEXT_CONTROL_VAL] & inhibit_mask);
|
||||
}
|
||||
|
||||
/* Switch ring mmio values (context). */
|
||||
static void switch_mmio(struct intel_vgpu *pre,
|
||||
struct intel_vgpu *next,
|
||||
@ -300,9 +462,6 @@ static void switch_mmio(struct intel_vgpu *pre,
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct intel_vgpu_submission *s;
|
||||
u32 *reg_state, ctx_ctrl;
|
||||
u32 inhibit_mask =
|
||||
_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
|
||||
struct engine_mmio *mmio;
|
||||
u32 old_v, new_v;
|
||||
|
||||
@ -310,10 +469,18 @@ static void switch_mmio(struct intel_vgpu *pre,
|
||||
if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
|
||||
switch_mocs(pre, next, ring_id);
|
||||
|
||||
for (mmio = dev_priv->gvt->engine_mmio_list;
|
||||
for (mmio = dev_priv->gvt->engine_mmio_list.mmio;
|
||||
i915_mmio_reg_valid(mmio->reg); mmio++) {
|
||||
if (mmio->ring_id != ring_id)
|
||||
continue;
|
||||
/*
|
||||
* No need to do save or restore of the mmio which is in context
|
||||
* state image on kabylake, it's initialized by lri command and
|
||||
* save or restore with context together.
|
||||
*/
|
||||
if (IS_KABYLAKE(dev_priv) && mmio->in_context)
|
||||
continue;
|
||||
|
||||
// save
|
||||
if (pre) {
|
||||
vgpu_vreg_t(pre, mmio->reg) = I915_READ_FW(mmio->reg);
|
||||
@ -327,16 +494,13 @@ static void switch_mmio(struct intel_vgpu *pre,
|
||||
// restore
|
||||
if (next) {
|
||||
s = &next->submission;
|
||||
reg_state =
|
||||
s->shadow_ctx->engine[ring_id].lrc_reg_state;
|
||||
ctx_ctrl = reg_state[CTX_CONTEXT_CONTROL_VAL];
|
||||
/*
|
||||
* if it is an inhibit context, load in_context mmio
|
||||
* into HW by mmio write. If it is not, skip this mmio
|
||||
* write.
|
||||
* No need to restore the mmio which is in context state
|
||||
* image if it's not inhibit context, it will restore
|
||||
* itself.
|
||||
*/
|
||||
if (mmio->in_context &&
|
||||
(ctx_ctrl & inhibit_mask) != inhibit_mask)
|
||||
!is_inhibit_context(s->shadow_ctx, ring_id))
|
||||
continue;
|
||||
|
||||
if (mmio->mask)
|
||||
@ -405,8 +569,16 @@ void intel_gvt_switch_mmio(struct intel_vgpu *pre,
|
||||
*/
|
||||
void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt)
|
||||
{
|
||||
struct engine_mmio *mmio;
|
||||
|
||||
if (IS_SKYLAKE(gvt->dev_priv) || IS_KABYLAKE(gvt->dev_priv))
|
||||
gvt->engine_mmio_list = gen9_engine_mmio_list;
|
||||
gvt->engine_mmio_list.mmio = gen9_engine_mmio_list;
|
||||
else
|
||||
gvt->engine_mmio_list = gen8_engine_mmio_list;
|
||||
gvt->engine_mmio_list.mmio = gen8_engine_mmio_list;
|
||||
|
||||
for (mmio = gvt->engine_mmio_list.mmio;
|
||||
i915_mmio_reg_valid(mmio->reg); mmio++) {
|
||||
if (mmio->in_context)
|
||||
gvt->engine_mmio_list.ctx_mmio_count[mmio->ring_id]++;
|
||||
}
|
||||
}
|
||||
|
@ -49,4 +49,9 @@ void intel_gvt_switch_mmio(struct intel_vgpu *pre,
|
||||
|
||||
void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt);
|
||||
|
||||
bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id);
|
||||
|
||||
int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu,
|
||||
struct i915_request *req);
|
||||
|
||||
#endif
|
||||
|
@ -154,54 +154,31 @@ static inline unsigned long intel_gvt_hypervisor_virt_to_mfn(void *p)
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_hypervisor_enable - set a guest page to write-protected
|
||||
* intel_gvt_hypervisor_enable_page_track - track a guest page
|
||||
* @vgpu: a vGPU
|
||||
* @t: page track data structure
|
||||
* @gfn: the gfn of guest
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code if failed.
|
||||
*/
|
||||
static inline int intel_gvt_hypervisor_enable_page_track(
|
||||
struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_page_track *t)
|
||||
struct intel_vgpu *vgpu, unsigned long gfn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (t->tracked)
|
||||
return 0;
|
||||
|
||||
ret = intel_gvt_host.mpt->set_wp_page(vgpu->handle, t->gfn);
|
||||
if (ret)
|
||||
return ret;
|
||||
t->tracked = true;
|
||||
atomic_inc(&vgpu->gtt.n_tracked_guest_page);
|
||||
return 0;
|
||||
return intel_gvt_host.mpt->enable_page_track(vgpu->handle, gfn);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_hypervisor_disable_page_track - remove the write-protection of a
|
||||
* guest page
|
||||
* intel_gvt_hypervisor_disable_page_track - untrack a guest page
|
||||
* @vgpu: a vGPU
|
||||
* @t: page track data structure
|
||||
* @gfn: the gfn of guest
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code if failed.
|
||||
*/
|
||||
static inline int intel_gvt_hypervisor_disable_page_track(
|
||||
struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_page_track *t)
|
||||
struct intel_vgpu *vgpu, unsigned long gfn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!t->tracked)
|
||||
return 0;
|
||||
|
||||
ret = intel_gvt_host.mpt->unset_wp_page(vgpu->handle, t->gfn);
|
||||
if (ret)
|
||||
return ret;
|
||||
t->tracked = false;
|
||||
atomic_dec(&vgpu->gtt.n_tracked_guest_page);
|
||||
return 0;
|
||||
return intel_gvt_host.mpt->disable_page_track(vgpu->handle, gfn);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -250,6 +227,34 @@ static inline unsigned long intel_gvt_hypervisor_gfn_to_mfn(
|
||||
return intel_gvt_host.mpt->gfn_to_mfn(vgpu->handle, gfn);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_hypervisor_dma_map_guest_page - setup dma map for guest page
|
||||
* @vgpu: a vGPU
|
||||
* @gpfn: guest pfn
|
||||
* @dma_addr: retrieve allocated dma addr
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, negative error code if failed.
|
||||
*/
|
||||
static inline int intel_gvt_hypervisor_dma_map_guest_page(
|
||||
struct intel_vgpu *vgpu, unsigned long gfn,
|
||||
dma_addr_t *dma_addr)
|
||||
{
|
||||
return intel_gvt_host.mpt->dma_map_guest_page(vgpu->handle, gfn,
|
||||
dma_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_hypervisor_dma_unmap_guest_page - cancel dma map for guest page
|
||||
* @vgpu: a vGPU
|
||||
* @dma_addr: the mapped dma addr
|
||||
*/
|
||||
static inline void intel_gvt_hypervisor_dma_unmap_guest_page(
|
||||
struct intel_vgpu *vgpu, dma_addr_t dma_addr)
|
||||
{
|
||||
intel_gvt_host.mpt->dma_unmap_guest_page(vgpu->handle, dma_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_hypervisor_map_gfn_to_mfn - map a GFN region to MFN
|
||||
* @vgpu: a vGPU
|
||||
|
184
drivers/gpu/drm/i915/gvt/page_track.c
Normal file
184
drivers/gpu/drm/i915/gvt/page_track.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright(c) 2011-2017 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 "i915_drv.h"
|
||||
#include "gvt.h"
|
||||
|
||||
/**
|
||||
* intel_vgpu_find_page_track - find page track rcord of guest page
|
||||
* @vgpu: a vGPU
|
||||
* @gfn: the gfn of guest page
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to struct intel_vgpu_page_track if found, else NULL returned.
|
||||
*/
|
||||
struct intel_vgpu_page_track *intel_vgpu_find_page_track(
|
||||
struct intel_vgpu *vgpu, unsigned long gfn)
|
||||
{
|
||||
return radix_tree_lookup(&vgpu->page_track_tree, gfn);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_vgpu_register_page_track - register a guest page to be tacked
|
||||
* @vgpu: a vGPU
|
||||
* @gfn: the gfn of guest page
|
||||
*
|
||||
* Returns:
|
||||
* zero on success, negative error code if failed.
|
||||
*/
|
||||
int intel_vgpu_register_page_track(struct intel_vgpu *vgpu, unsigned long gfn,
|
||||
gvt_page_track_handler_t handler, void *priv)
|
||||
{
|
||||
struct intel_vgpu_page_track *track;
|
||||
int ret;
|
||||
|
||||
track = intel_vgpu_find_page_track(vgpu, gfn);
|
||||
if (track)
|
||||
return -EEXIST;
|
||||
|
||||
track = kzalloc(sizeof(*track), GFP_KERNEL);
|
||||
if (!track)
|
||||
return -ENOMEM;
|
||||
|
||||
track->handler = handler;
|
||||
track->priv_data = priv;
|
||||
|
||||
ret = radix_tree_insert(&vgpu->page_track_tree, gfn, track);
|
||||
if (ret) {
|
||||
kfree(track);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_vgpu_unregister_page_track - unregister the tracked guest page
|
||||
* @vgpu: a vGPU
|
||||
* @gfn: the gfn of guest page
|
||||
*
|
||||
*/
|
||||
void intel_vgpu_unregister_page_track(struct intel_vgpu *vgpu,
|
||||
unsigned long gfn)
|
||||
{
|
||||
struct intel_vgpu_page_track *track;
|
||||
|
||||
track = radix_tree_delete(&vgpu->page_track_tree, gfn);
|
||||
if (track) {
|
||||
if (track->tracked)
|
||||
intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
|
||||
kfree(track);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_vgpu_enable_page_track - set write-protection on guest page
|
||||
* @vgpu: a vGPU
|
||||
* @gfn: the gfn of guest page
|
||||
*
|
||||
* Returns:
|
||||
* zero on success, negative error code if failed.
|
||||
*/
|
||||
int intel_vgpu_enable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
|
||||
{
|
||||
struct intel_vgpu_page_track *track;
|
||||
int ret;
|
||||
|
||||
track = intel_vgpu_find_page_track(vgpu, gfn);
|
||||
if (!track)
|
||||
return -ENXIO;
|
||||
|
||||
if (track->tracked)
|
||||
return 0;
|
||||
|
||||
ret = intel_gvt_hypervisor_enable_page_track(vgpu, gfn);
|
||||
if (ret)
|
||||
return ret;
|
||||
track->tracked = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_vgpu_enable_page_track - cancel write-protection on guest page
|
||||
* @vgpu: a vGPU
|
||||
* @gfn: the gfn of guest page
|
||||
*
|
||||
* Returns:
|
||||
* zero on success, negative error code if failed.
|
||||
*/
|
||||
int intel_vgpu_disable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
|
||||
{
|
||||
struct intel_vgpu_page_track *track;
|
||||
int ret;
|
||||
|
||||
track = intel_vgpu_find_page_track(vgpu, gfn);
|
||||
if (!track)
|
||||
return -ENXIO;
|
||||
|
||||
if (!track->tracked)
|
||||
return 0;
|
||||
|
||||
ret = intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
|
||||
if (ret)
|
||||
return ret;
|
||||
track->tracked = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_vgpu_page_track_handler - called when write to write-protected page
|
||||
* @vgpu: a vGPU
|
||||
* @gpa: the gpa of this write
|
||||
* @data: the writed data
|
||||
* @bytes: the length of this write
|
||||
*
|
||||
* Returns:
|
||||
* zero on success, negative error code if failed.
|
||||
*/
|
||||
int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa,
|
||||
void *data, unsigned int bytes)
|
||||
{
|
||||
struct intel_gvt *gvt = vgpu->gvt;
|
||||
struct intel_vgpu_page_track *page_track;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&gvt->lock);
|
||||
|
||||
page_track = intel_vgpu_find_page_track(vgpu, gpa >> PAGE_SHIFT);
|
||||
if (!page_track) {
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(vgpu->failsafe)) {
|
||||
/* Remove write protection to prevent furture traps. */
|
||||
intel_vgpu_disable_page_track(vgpu, gpa >> PAGE_SHIFT);
|
||||
} else {
|
||||
ret = page_track->handler(page_track, gpa, data, bytes);
|
||||
if (ret)
|
||||
gvt_err("guest page write error, gpa %llx\n", gpa);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&gvt->lock);
|
||||
return ret;
|
||||
}
|
56
drivers/gpu/drm/i915/gvt/page_track.h
Normal file
56
drivers/gpu/drm/i915/gvt/page_track.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright(c) 2011-2017 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_PAGE_TRACK_H_
|
||||
#define _GVT_PAGE_TRACK_H_
|
||||
|
||||
struct intel_vgpu_page_track;
|
||||
|
||||
typedef int (*gvt_page_track_handler_t)(
|
||||
struct intel_vgpu_page_track *page_track,
|
||||
u64 gpa, void *data, int bytes);
|
||||
|
||||
/* Track record for a write-protected guest page. */
|
||||
struct intel_vgpu_page_track {
|
||||
gvt_page_track_handler_t handler;
|
||||
bool tracked;
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
struct intel_vgpu_page_track *intel_vgpu_find_page_track(
|
||||
struct intel_vgpu *vgpu, unsigned long gfn);
|
||||
|
||||
int intel_vgpu_register_page_track(struct intel_vgpu *vgpu,
|
||||
unsigned long gfn, gvt_page_track_handler_t handler,
|
||||
void *priv);
|
||||
void intel_vgpu_unregister_page_track(struct intel_vgpu *vgpu,
|
||||
unsigned long gfn);
|
||||
|
||||
int intel_vgpu_enable_page_track(struct intel_vgpu *vgpu, unsigned long gfn);
|
||||
int intel_vgpu_disable_page_track(struct intel_vgpu *vgpu, unsigned long gfn);
|
||||
|
||||
int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa,
|
||||
void *data, unsigned int bytes);
|
||||
|
||||
#endif
|
@ -103,9 +103,8 @@ static void gvt_balance_timeslice(struct gvt_sched_data *sched_data)
|
||||
|
||||
list_for_each(pos, &sched_data->lru_runq_head) {
|
||||
vgpu_data = container_of(pos, struct vgpu_sched_data, lru_list);
|
||||
fair_timeslice = ms_to_ktime(GVT_TS_BALANCE_PERIOD_MS) *
|
||||
vgpu_data->sched_ctl.weight /
|
||||
total_weight;
|
||||
fair_timeslice = ktime_divns(ms_to_ktime(GVT_TS_BALANCE_PERIOD_MS),
|
||||
total_weight) * vgpu_data->sched_ctl.weight;
|
||||
|
||||
vgpu_data->allocated_ts = fair_timeslice;
|
||||
vgpu_data->left_ts = vgpu_data->allocated_ts;
|
||||
|
@ -113,7 +113,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
|
||||
#undef COPY_REG
|
||||
|
||||
set_context_pdp_root_pointer(shadow_ring_context,
|
||||
workload->shadow_mm->shadow_page_table);
|
||||
(void *)workload->shadow_mm->ppgtt_mm.shadow_pdps);
|
||||
|
||||
intel_gvt_hypervisor_read_gpa(vgpu,
|
||||
workload->ring_context_gpa +
|
||||
@ -225,6 +225,11 @@ static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload)
|
||||
struct intel_vgpu *vgpu = workload->vgpu;
|
||||
void *shadow_ring_buffer_va;
|
||||
u32 *cs;
|
||||
struct i915_request *req = workload->req;
|
||||
|
||||
if (IS_KABYLAKE(req->i915) &&
|
||||
is_inhibit_context(req->ctx, req->engine->id))
|
||||
intel_vgpu_restore_inhibit_context(vgpu, req);
|
||||
|
||||
/* allocate shadow ring buffer */
|
||||
cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
|
||||
@ -1132,7 +1137,7 @@ void intel_vgpu_destroy_workload(struct intel_vgpu_workload *workload)
|
||||
struct intel_vgpu_submission *s = &workload->vgpu->submission;
|
||||
|
||||
if (workload->shadow_mm)
|
||||
intel_gvt_mm_unreference(workload->shadow_mm);
|
||||
intel_vgpu_mm_put(workload->shadow_mm);
|
||||
|
||||
kmem_cache_free(s->workloads, workload);
|
||||
}
|
||||
@ -1181,32 +1186,27 @@ static int prepare_mm(struct intel_vgpu_workload *workload)
|
||||
struct execlist_ctx_descriptor_format *desc = &workload->ctx_desc;
|
||||
struct intel_vgpu_mm *mm;
|
||||
struct intel_vgpu *vgpu = workload->vgpu;
|
||||
int page_table_level;
|
||||
u32 pdp[8];
|
||||
intel_gvt_gtt_type_t root_entry_type;
|
||||
u64 pdps[GVT_RING_CTX_NR_PDPS];
|
||||
|
||||
if (desc->addressing_mode == 1) { /* legacy 32-bit */
|
||||
page_table_level = 3;
|
||||
} else if (desc->addressing_mode == 3) { /* legacy 64 bit */
|
||||
page_table_level = 4;
|
||||
} else {
|
||||
switch (desc->addressing_mode) {
|
||||
case 1: /* legacy 32-bit */
|
||||
root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
|
||||
break;
|
||||
case 3: /* legacy 64-bit */
|
||||
root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
|
||||
break;
|
||||
default:
|
||||
gvt_vgpu_err("Advanced Context mode(SVM) is not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
read_guest_pdps(workload->vgpu, workload->ring_context_gpa, pdp);
|
||||
read_guest_pdps(workload->vgpu, workload->ring_context_gpa, (void *)pdps);
|
||||
|
||||
mm = intel_vgpu_find_ppgtt_mm(workload->vgpu, page_table_level, pdp);
|
||||
if (mm) {
|
||||
intel_gvt_mm_reference(mm);
|
||||
} else {
|
||||
mm = intel_vgpu_get_ppgtt_mm(workload->vgpu, root_entry_type, pdps);
|
||||
if (IS_ERR(mm))
|
||||
return PTR_ERR(mm);
|
||||
|
||||
mm = intel_vgpu_create_mm(workload->vgpu, INTEL_GVT_MM_PPGTT,
|
||||
pdp, page_table_level, 0);
|
||||
if (IS_ERR(mm)) {
|
||||
gvt_vgpu_err("fail to create mm object.\n");
|
||||
return PTR_ERR(mm);
|
||||
}
|
||||
}
|
||||
workload->shadow_mm = mm;
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,10 +113,10 @@ TRACE_EVENT(gma_index,
|
||||
);
|
||||
|
||||
TRACE_EVENT(gma_translate,
|
||||
TP_PROTO(int id, char *type, int ring_id, int pt_level,
|
||||
TP_PROTO(int id, char *type, int ring_id, int root_entry_type,
|
||||
unsigned long gma, unsigned long gpa),
|
||||
|
||||
TP_ARGS(id, type, ring_id, pt_level, gma, gpa),
|
||||
TP_ARGS(id, type, ring_id, root_entry_type, gma, gpa),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, buf, MAX_BUF_LEN)
|
||||
@ -124,8 +124,8 @@ TRACE_EVENT(gma_translate,
|
||||
|
||||
TP_fast_assign(
|
||||
snprintf(__entry->buf, MAX_BUF_LEN,
|
||||
"VM%d %s ring %d pt_level %d gma 0x%lx -> gpa 0x%lx\n",
|
||||
id, type, ring_id, pt_level, gma, gpa);
|
||||
"VM%d %s ring %d root_entry_type %d gma 0x%lx -> gpa 0x%lx\n",
|
||||
id, type, ring_id, root_entry_type, gma, gpa);
|
||||
),
|
||||
|
||||
TP_printk("%s", __entry->buf)
|
||||
@ -168,7 +168,7 @@ TRACE_EVENT(spt_change,
|
||||
TP_printk("%s", __entry->buf)
|
||||
);
|
||||
|
||||
TRACE_EVENT(gpt_change,
|
||||
TRACE_EVENT(spt_guest_change,
|
||||
TP_PROTO(int id, const char *tag, void *spt, int type, u64 v,
|
||||
unsigned long index),
|
||||
|
||||
|
@ -354,6 +354,7 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
|
||||
vgpu->gvt = gvt;
|
||||
vgpu->sched_ctl.weight = param->weight;
|
||||
INIT_LIST_HEAD(&vgpu->dmabuf_obj_list_head);
|
||||
INIT_RADIX_TREE(&vgpu->page_track_tree, GFP_KERNEL);
|
||||
idr_init(&vgpu->object_idr);
|
||||
intel_vgpu_init_cfg_space(vgpu, param->primary);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user