mirror of https://gitee.com/openkylin/linux.git
Merge tag 'drm-intel-next-2018-03-08' of git://anongit.freedesktop.org/drm/drm-intel into drm-next
UAPI Changes: - Query uAPI interface (used for GPU topology information currently) * Mesa: https://patchwork.freedesktop.org/series/38795/ Driver Changes: - Increase PSR2 size for CNL (DK) - Avoid retraining LSPCON link unnecessarily (Ville) - Decrease request signaling latency (Chris) - GuC error capture fix (Daniele) * tag 'drm-intel-next-2018-03-08' of git://anongit.freedesktop.org/drm/drm-intel: (127 commits) drm/i915: Update DRIVER_DATE to 20180308 drm/i915: add schedule out notification of preempted but completed request drm/i915: expose rcs topology through query uAPI drm/i915: add query uAPI drm/i915: add rcs topology to error state drm/i915/debugfs: add rcs topology entry drm/i915/debugfs: reuse max slice/subslices already stored in sseu drm/i915: store all subslice masks drm/i915/guc: work around gcc-4.4.4 union initializer issue drm/i915/cnl: Add Wa_2201832410 drm/i915/icl: Gen11 forcewake support drm/i915/icl: Add Indirect Context Offset for Gen11 drm/i915/icl: Enhanced execution list support drm/i915/icl: new context descriptor support drm/i915/icl: Correctly initialize the Gen11 engines drm/i915: Assert that the request is indeed complete when signaled from irq drm/i915: Handle changing enable_fbc parameter at runtime better. drm/i915: Track whether the DP link is trained or not drm/i915: Nuke intel_dp->channel_eq_status drm/i915: Move SST DP link retraining into the ->post_hotplug() hook ...
This commit is contained in:
commit
963976cfe9
|
@ -450,5 +450,12 @@ See drivers/gpu/drm/amd/display/TODO for tasks.
|
|||
|
||||
Contact: Harry Wentland, Alex Deucher
|
||||
|
||||
i915
|
||||
----
|
||||
|
||||
- Our early/late pm callbacks could be removed in favour of using
|
||||
device_link_add to model the dependency between i915 and snd_had. See
|
||||
https://dri.freedesktop.org/docs/drm/driver-api/device_link.html
|
||||
|
||||
Outside DRM
|
||||
===========
|
||||
|
|
|
@ -1247,12 +1247,15 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc)
|
|||
EXPORT_SYMBOL(drm_crtc_vblank_on);
|
||||
|
||||
/**
|
||||
* drm_vblank_restore - estimated vblanks using timestamps and update it.
|
||||
* drm_vblank_restore - estimate missed vblanks and update vblank count.
|
||||
* @dev: DRM device
|
||||
* @pipe: CRTC index
|
||||
*
|
||||
* Power manamement features can cause frame counter resets between vblank
|
||||
* disable and enable. Drivers can then use this function in their
|
||||
* &drm_crtc_funcs.enable_vblank implementation to estimate the vblanks since
|
||||
* the last &drm_crtc_funcs.disable_vblank.
|
||||
* disable and enable. Drivers can use this function in their
|
||||
* &drm_crtc_funcs.enable_vblank implementation to estimate missed vblanks since
|
||||
* the last &drm_crtc_funcs.disable_vblank using timestamps and update the
|
||||
* vblank counter.
|
||||
*
|
||||
* This function is the legacy version of drm_crtc_vblank_restore().
|
||||
*/
|
||||
|
@ -1293,11 +1296,14 @@ void drm_vblank_restore(struct drm_device *dev, unsigned int pipe)
|
|||
EXPORT_SYMBOL(drm_vblank_restore);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_restore - estimate vblanks using timestamps and update it.
|
||||
* drm_crtc_vblank_restore - estimate missed vblanks and update vblank count.
|
||||
* @crtc: CRTC in question
|
||||
*
|
||||
* Power manamement features can cause frame counter resets between vblank
|
||||
* disable and enable. Drivers can then use this function in their
|
||||
* &drm_crtc_funcs.enable_vblank implementation to estimate the vblanks since
|
||||
* the last &drm_crtc_funcs.disable_vblank.
|
||||
* disable and enable. Drivers can use this function in their
|
||||
* &drm_crtc_funcs.enable_vblank implementation to estimate missed vblanks since
|
||||
* the last &drm_crtc_funcs.disable_vblank using timestamps and update the
|
||||
* vblank counter.
|
||||
*/
|
||||
void drm_crtc_vblank_restore(struct drm_crtc *crtc)
|
||||
{
|
||||
|
|
|
@ -63,13 +63,14 @@ i915-y += i915_cmd_parser.o \
|
|||
i915_gem.o \
|
||||
i915_gem_object.o \
|
||||
i915_gem_render_state.o \
|
||||
i915_gem_request.o \
|
||||
i915_gem_shrinker.o \
|
||||
i915_gem_stolen.o \
|
||||
i915_gem_tiling.o \
|
||||
i915_gem_timeline.o \
|
||||
i915_gem_userptr.o \
|
||||
i915_gemfs.o \
|
||||
i915_query.o \
|
||||
i915_request.o \
|
||||
i915_trace_points.o \
|
||||
i915_vma.o \
|
||||
intel_breadcrumbs.o \
|
||||
|
@ -89,7 +90,8 @@ i915-y += intel_uc.o \
|
|||
intel_guc_fw.o \
|
||||
intel_guc_log.o \
|
||||
intel_guc_submission.o \
|
||||
intel_huc.o
|
||||
intel_huc.o \
|
||||
intel_huc_fw.o
|
||||
|
||||
# autogenerated null render state
|
||||
i915-y += intel_renderstate_gen6.o \
|
||||
|
|
|
@ -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 @@ static int kvmgt_write_protect_add(unsigned long handle, u64 gfn)
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 +
|
||||
|
@ -126,7 +126,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline bool is_gvt_request(struct drm_i915_gem_request *req)
|
||||
static inline bool is_gvt_request(struct i915_request *req)
|
||||
{
|
||||
return i915_gem_context_force_single_submission(req->ctx);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ static void save_ring_hw_state(struct intel_vgpu *vgpu, int ring_id)
|
|||
static int shadow_context_status_change(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct drm_i915_gem_request *req = (struct drm_i915_gem_request *)data;
|
||||
struct i915_request *req = data;
|
||||
struct intel_gvt *gvt = container_of(nb, struct intel_gvt,
|
||||
shadow_ctx_notifier_block[req->engine->id]);
|
||||
struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
|
||||
|
@ -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));
|
||||
|
@ -333,13 +338,13 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload)
|
|||
int ring_id = workload->ring_id;
|
||||
struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv;
|
||||
struct intel_engine_cs *engine = dev_priv->engine[ring_id];
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct intel_vgpu *vgpu = workload->vgpu;
|
||||
struct intel_vgpu_submission *s = &vgpu->submission;
|
||||
struct i915_gem_context *shadow_ctx = s->shadow_ctx;
|
||||
int ret;
|
||||
|
||||
rq = i915_gem_request_alloc(dev_priv->engine[ring_id], shadow_ctx);
|
||||
rq = i915_request_alloc(dev_priv->engine[ring_id], shadow_ctx);
|
||||
if (IS_ERR(rq)) {
|
||||
gvt_vgpu_err("fail to allocate gem request\n");
|
||||
ret = PTR_ERR(rq);
|
||||
|
@ -348,7 +353,7 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload)
|
|||
|
||||
gvt_dbg_sched("ring id %d get i915 gem request %p\n", ring_id, rq);
|
||||
|
||||
workload->req = i915_gem_request_get(rq);
|
||||
workload->req = i915_request_get(rq);
|
||||
ret = copy_workload_to_ring_buffer(workload);
|
||||
if (ret)
|
||||
goto err_unpin;
|
||||
|
@ -582,7 +587,7 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
|
|||
if (!IS_ERR_OR_NULL(workload->req)) {
|
||||
gvt_dbg_sched("ring id %d submit workload to i915 %p\n",
|
||||
ring_id, workload->req);
|
||||
i915_add_request(workload->req);
|
||||
i915_request_add(workload->req);
|
||||
workload->dispatched = true;
|
||||
}
|
||||
|
||||
|
@ -769,7 +774,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
|
|||
workload->status = 0;
|
||||
}
|
||||
|
||||
i915_gem_request_put(fetch_and_zero(&workload->req));
|
||||
i915_request_put(fetch_and_zero(&workload->req));
|
||||
|
||||
if (!workload->status && !(vgpu->resetting_eng &
|
||||
ENGINE_MASK(ring_id))) {
|
||||
|
@ -886,7 +891,7 @@ static int workload_thread(void *priv)
|
|||
|
||||
gvt_dbg_sched("ring id %d wait workload %p\n",
|
||||
workload->ring_id, workload);
|
||||
i915_wait_request(workload->req, 0, MAX_SCHEDULE_TIMEOUT);
|
||||
i915_request_wait(workload->req, 0, MAX_SCHEDULE_TIMEOUT);
|
||||
|
||||
complete:
|
||||
gvt_dbg_sched("will complete workload %p, status: %d\n",
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ struct intel_shadow_wa_ctx {
|
|||
struct intel_vgpu_workload {
|
||||
struct intel_vgpu *vgpu;
|
||||
int ring_id;
|
||||
struct drm_i915_gem_request *req;
|
||||
struct i915_request *req;
|
||||
/* if this workload has been dispatched to i915? */
|
||||
bool dispatched;
|
||||
bool shadowed;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -519,7 +519,7 @@ static int i915_gem_object_info(struct seq_file *m, void *data)
|
|||
list_for_each_entry_reverse(file, &dev->filelist, lhead) {
|
||||
struct file_stats stats;
|
||||
struct drm_i915_file_private *file_priv = file->driver_priv;
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
struct task_struct *task;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
@ -536,7 +536,7 @@ static int i915_gem_object_info(struct seq_file *m, void *data)
|
|||
* Therefore, we need to protect this ->comm access using RCU.
|
||||
*/
|
||||
request = list_first_entry_or_null(&file_priv->mm.request_list,
|
||||
struct drm_i915_gem_request,
|
||||
struct i915_request,
|
||||
client_link);
|
||||
rcu_read_lock();
|
||||
task = pid_task(request && request->ctx->pid ?
|
||||
|
@ -646,6 +646,56 @@ static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void gen8_display_interrupt_info(struct seq_file *m)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = node_to_i915(m->private);
|
||||
int pipe;
|
||||
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
enum intel_display_power_domain power_domain;
|
||||
|
||||
power_domain = POWER_DOMAIN_PIPE(pipe);
|
||||
if (!intel_display_power_get_if_enabled(dev_priv,
|
||||
power_domain)) {
|
||||
seq_printf(m, "Pipe %c power disabled\n",
|
||||
pipe_name(pipe));
|
||||
continue;
|
||||
}
|
||||
seq_printf(m, "Pipe %c IMR:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(GEN8_DE_PIPE_IMR(pipe)));
|
||||
seq_printf(m, "Pipe %c IIR:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(GEN8_DE_PIPE_IIR(pipe)));
|
||||
seq_printf(m, "Pipe %c IER:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(GEN8_DE_PIPE_IER(pipe)));
|
||||
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
}
|
||||
|
||||
seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
|
||||
I915_READ(GEN8_DE_PORT_IMR));
|
||||
seq_printf(m, "Display Engine port interrupt identity:\t%08x\n",
|
||||
I915_READ(GEN8_DE_PORT_IIR));
|
||||
seq_printf(m, "Display Engine port interrupt enable:\t%08x\n",
|
||||
I915_READ(GEN8_DE_PORT_IER));
|
||||
|
||||
seq_printf(m, "Display Engine misc interrupt mask:\t%08x\n",
|
||||
I915_READ(GEN8_DE_MISC_IMR));
|
||||
seq_printf(m, "Display Engine misc interrupt identity:\t%08x\n",
|
||||
I915_READ(GEN8_DE_MISC_IIR));
|
||||
seq_printf(m, "Display Engine misc interrupt enable:\t%08x\n",
|
||||
I915_READ(GEN8_DE_MISC_IER));
|
||||
|
||||
seq_printf(m, "PCU interrupt mask:\t%08x\n",
|
||||
I915_READ(GEN8_PCU_IMR));
|
||||
seq_printf(m, "PCU interrupt identity:\t%08x\n",
|
||||
I915_READ(GEN8_PCU_IIR));
|
||||
seq_printf(m, "PCU interrupt enable:\t%08x\n",
|
||||
I915_READ(GEN8_PCU_IER));
|
||||
}
|
||||
|
||||
static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = node_to_i915(m->private);
|
||||
|
@ -709,6 +759,27 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
|||
I915_READ(GEN8_PCU_IIR));
|
||||
seq_printf(m, "PCU interrupt enable:\t%08x\n",
|
||||
I915_READ(GEN8_PCU_IER));
|
||||
} else if (INTEL_GEN(dev_priv) >= 11) {
|
||||
seq_printf(m, "Master Interrupt Control: %08x\n",
|
||||
I915_READ(GEN11_GFX_MSTR_IRQ));
|
||||
|
||||
seq_printf(m, "Render/Copy Intr Enable: %08x\n",
|
||||
I915_READ(GEN11_RENDER_COPY_INTR_ENABLE));
|
||||
seq_printf(m, "VCS/VECS Intr Enable: %08x\n",
|
||||
I915_READ(GEN11_VCS_VECS_INTR_ENABLE));
|
||||
seq_printf(m, "GUC/SG Intr Enable:\t %08x\n",
|
||||
I915_READ(GEN11_GUC_SG_INTR_ENABLE));
|
||||
seq_printf(m, "GPM/WGBOXPERF Intr Enable: %08x\n",
|
||||
I915_READ(GEN11_GPM_WGBOXPERF_INTR_ENABLE));
|
||||
seq_printf(m, "Crypto Intr Enable:\t %08x\n",
|
||||
I915_READ(GEN11_CRYPTO_RSVD_INTR_ENABLE));
|
||||
seq_printf(m, "GUnit/CSME Intr Enable:\t %08x\n",
|
||||
I915_READ(GEN11_GUNIT_CSME_INTR_ENABLE));
|
||||
|
||||
seq_printf(m, "Display Interrupt Control:\t%08x\n",
|
||||
I915_READ(GEN11_DISPLAY_INT_CTL));
|
||||
|
||||
gen8_display_interrupt_info(m);
|
||||
} else if (INTEL_GEN(dev_priv) >= 8) {
|
||||
seq_printf(m, "Master Interrupt Control:\t%08x\n",
|
||||
I915_READ(GEN8_MASTER_IRQ));
|
||||
|
@ -722,49 +793,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
|||
i, I915_READ(GEN8_GT_IER(i)));
|
||||
}
|
||||
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
enum intel_display_power_domain power_domain;
|
||||
|
||||
power_domain = POWER_DOMAIN_PIPE(pipe);
|
||||
if (!intel_display_power_get_if_enabled(dev_priv,
|
||||
power_domain)) {
|
||||
seq_printf(m, "Pipe %c power disabled\n",
|
||||
pipe_name(pipe));
|
||||
continue;
|
||||
}
|
||||
seq_printf(m, "Pipe %c IMR:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(GEN8_DE_PIPE_IMR(pipe)));
|
||||
seq_printf(m, "Pipe %c IIR:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(GEN8_DE_PIPE_IIR(pipe)));
|
||||
seq_printf(m, "Pipe %c IER:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(GEN8_DE_PIPE_IER(pipe)));
|
||||
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
}
|
||||
|
||||
seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
|
||||
I915_READ(GEN8_DE_PORT_IMR));
|
||||
seq_printf(m, "Display Engine port interrupt identity:\t%08x\n",
|
||||
I915_READ(GEN8_DE_PORT_IIR));
|
||||
seq_printf(m, "Display Engine port interrupt enable:\t%08x\n",
|
||||
I915_READ(GEN8_DE_PORT_IER));
|
||||
|
||||
seq_printf(m, "Display Engine misc interrupt mask:\t%08x\n",
|
||||
I915_READ(GEN8_DE_MISC_IMR));
|
||||
seq_printf(m, "Display Engine misc interrupt identity:\t%08x\n",
|
||||
I915_READ(GEN8_DE_MISC_IIR));
|
||||
seq_printf(m, "Display Engine misc interrupt enable:\t%08x\n",
|
||||
I915_READ(GEN8_DE_MISC_IER));
|
||||
|
||||
seq_printf(m, "PCU interrupt mask:\t%08x\n",
|
||||
I915_READ(GEN8_PCU_IMR));
|
||||
seq_printf(m, "PCU interrupt identity:\t%08x\n",
|
||||
I915_READ(GEN8_PCU_IIR));
|
||||
seq_printf(m, "PCU interrupt enable:\t%08x\n",
|
||||
I915_READ(GEN8_PCU_IER));
|
||||
gen8_display_interrupt_info(m);
|
||||
} else if (IS_VALLEYVIEW(dev_priv)) {
|
||||
seq_printf(m, "Display IER:\t%08x\n",
|
||||
I915_READ(VLV_IER));
|
||||
|
@ -846,13 +875,35 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
|||
seq_printf(m, "Graphics Interrupt mask: %08x\n",
|
||||
I915_READ(GTIMR));
|
||||
}
|
||||
if (INTEL_GEN(dev_priv) >= 6) {
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 11) {
|
||||
seq_printf(m, "RCS Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_RCS0_RSVD_INTR_MASK));
|
||||
seq_printf(m, "BCS Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_BCS_RSVD_INTR_MASK));
|
||||
seq_printf(m, "VCS0/VCS1 Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_VCS0_VCS1_INTR_MASK));
|
||||
seq_printf(m, "VCS2/VCS3 Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_VCS2_VCS3_INTR_MASK));
|
||||
seq_printf(m, "VECS0/VECS1 Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_VECS0_VECS1_INTR_MASK));
|
||||
seq_printf(m, "GUC/SG Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_GUC_SG_INTR_MASK));
|
||||
seq_printf(m, "GPM/WGBOXPERF Intr Mask: %08x\n",
|
||||
I915_READ(GEN11_GPM_WGBOXPERF_INTR_MASK));
|
||||
seq_printf(m, "Crypto Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_CRYPTO_RSVD_INTR_MASK));
|
||||
seq_printf(m, "Gunit/CSME Intr Mask:\t %08x\n",
|
||||
I915_READ(GEN11_GUNIT_CSME_INTR_MASK));
|
||||
|
||||
} else if (INTEL_GEN(dev_priv) >= 6) {
|
||||
for_each_engine(engine, dev_priv, id) {
|
||||
seq_printf(m,
|
||||
"Graphics Interrupt mask (%s): %08x\n",
|
||||
engine->name, I915_READ_IMR(engine));
|
||||
}
|
||||
}
|
||||
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
|
||||
return 0;
|
||||
|
@ -3150,6 +3201,16 @@ static int i915_engine_info(struct seq_file *m, void *unused)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int i915_rcs_topology(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = node_to_i915(m->private);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
|
||||
intel_device_info_dump_topology(&INTEL_INFO(dev_priv)->sseu, &p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_shrinker_info(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_i915_private *i915 = node_to_i915(m->private);
|
||||
|
@ -3926,7 +3987,8 @@ i915_wedged_set(void *data, u64 val)
|
|||
engine->hangcheck.stalled = true;
|
||||
}
|
||||
|
||||
i915_handle_error(i915, val, "Manually setting wedged to %llu", val);
|
||||
i915_handle_error(i915, val, "Manually set wedged engine mask = %llx",
|
||||
val);
|
||||
|
||||
wait_on_bit(&i915->gpu_error.flags,
|
||||
I915_RESET_HANDOFF,
|
||||
|
@ -4060,7 +4122,7 @@ i915_drop_caches_set(void *data, u64 val)
|
|||
I915_WAIT_LOCKED);
|
||||
|
||||
if (val & DROP_RETIRE)
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
i915_retire_requests(dev_priv);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
@ -4271,7 +4333,7 @@ static void cherryview_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
continue;
|
||||
|
||||
sseu->slice_mask = BIT(0);
|
||||
sseu->subslice_mask |= BIT(ss);
|
||||
sseu->subslice_mask[0] |= BIT(ss);
|
||||
eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
|
||||
((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
|
||||
((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
|
||||
|
@ -4286,11 +4348,11 @@ static void gen10_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
struct sseu_dev_info *sseu)
|
||||
{
|
||||
const struct intel_device_info *info = INTEL_INFO(dev_priv);
|
||||
int s_max = 6, ss_max = 4;
|
||||
int s, ss;
|
||||
u32 s_reg[s_max], eu_reg[2 * s_max], eu_mask[2];
|
||||
u32 s_reg[info->sseu.max_slices];
|
||||
u32 eu_reg[2 * info->sseu.max_subslices], eu_mask[2];
|
||||
|
||||
for (s = 0; s < s_max; s++) {
|
||||
for (s = 0; s < info->sseu.max_slices; s++) {
|
||||
/*
|
||||
* FIXME: Valid SS Mask respects the spec and read
|
||||
* only valid bits for those registers, excluding reserverd
|
||||
|
@ -4312,15 +4374,15 @@ static void gen10_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
GEN9_PGCTL_SSB_EU210_ACK |
|
||||
GEN9_PGCTL_SSB_EU311_ACK;
|
||||
|
||||
for (s = 0; s < s_max; s++) {
|
||||
for (s = 0; s < info->sseu.max_slices; s++) {
|
||||
if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
|
||||
/* skip disabled slice */
|
||||
continue;
|
||||
|
||||
sseu->slice_mask |= BIT(s);
|
||||
sseu->subslice_mask = info->sseu.subslice_mask;
|
||||
sseu->subslice_mask[s] = info->sseu.subslice_mask[s];
|
||||
|
||||
for (ss = 0; ss < ss_max; ss++) {
|
||||
for (ss = 0; ss < info->sseu.max_subslices; ss++) {
|
||||
unsigned int eu_cnt;
|
||||
|
||||
if (!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
|
||||
|
@ -4340,17 +4402,12 @@ static void gen10_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
static void gen9_sseu_device_status(struct drm_i915_private *dev_priv,
|
||||
struct sseu_dev_info *sseu)
|
||||
{
|
||||
int s_max = 3, ss_max = 4;
|
||||
const struct intel_device_info *info = INTEL_INFO(dev_priv);
|
||||
int s, ss;
|
||||
u32 s_reg[s_max], eu_reg[2*s_max], eu_mask[2];
|
||||
u32 s_reg[info->sseu.max_slices];
|
||||
u32 eu_reg[2 * info->sseu.max_subslices], eu_mask[2];
|
||||
|
||||
/* BXT has a single slice and at most 3 subslices. */
|
||||
if (IS_GEN9_LP(dev_priv)) {
|
||||
s_max = 1;
|
||||
ss_max = 3;
|
||||
}
|
||||
|
||||
for (s = 0; s < s_max; s++) {
|
||||
for (s = 0; s < info->sseu.max_slices; s++) {
|
||||
s_reg[s] = I915_READ(GEN9_SLICE_PGCTL_ACK(s));
|
||||
eu_reg[2*s] = I915_READ(GEN9_SS01_EU_PGCTL_ACK(s));
|
||||
eu_reg[2*s + 1] = I915_READ(GEN9_SS23_EU_PGCTL_ACK(s));
|
||||
|
@ -4365,7 +4422,7 @@ static void gen9_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
GEN9_PGCTL_SSB_EU210_ACK |
|
||||
GEN9_PGCTL_SSB_EU311_ACK;
|
||||
|
||||
for (s = 0; s < s_max; s++) {
|
||||
for (s = 0; s < info->sseu.max_slices; s++) {
|
||||
if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
|
||||
/* skip disabled slice */
|
||||
continue;
|
||||
|
@ -4373,10 +4430,10 @@ static void gen9_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
sseu->slice_mask |= BIT(s);
|
||||
|
||||
if (IS_GEN9_BC(dev_priv))
|
||||
sseu->subslice_mask =
|
||||
INTEL_INFO(dev_priv)->sseu.subslice_mask;
|
||||
sseu->subslice_mask[s] =
|
||||
INTEL_INFO(dev_priv)->sseu.subslice_mask[s];
|
||||
|
||||
for (ss = 0; ss < ss_max; ss++) {
|
||||
for (ss = 0; ss < info->sseu.max_subslices; ss++) {
|
||||
unsigned int eu_cnt;
|
||||
|
||||
if (IS_GEN9_LP(dev_priv)) {
|
||||
|
@ -4384,7 +4441,7 @@ static void gen9_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
/* skip disabled subslice */
|
||||
continue;
|
||||
|
||||
sseu->subslice_mask |= BIT(ss);
|
||||
sseu->subslice_mask[s] |= BIT(ss);
|
||||
}
|
||||
|
||||
eu_cnt = 2 * hweight32(eu_reg[2*s + ss/2] &
|
||||
|
@ -4406,9 +4463,12 @@ static void broadwell_sseu_device_status(struct drm_i915_private *dev_priv,
|
|||
sseu->slice_mask = slice_info & GEN8_LSLICESTAT_MASK;
|
||||
|
||||
if (sseu->slice_mask) {
|
||||
sseu->subslice_mask = INTEL_INFO(dev_priv)->sseu.subslice_mask;
|
||||
sseu->eu_per_subslice =
|
||||
INTEL_INFO(dev_priv)->sseu.eu_per_subslice;
|
||||
for (s = 0; s < fls(sseu->slice_mask); s++) {
|
||||
sseu->subslice_mask[s] =
|
||||
INTEL_INFO(dev_priv)->sseu.subslice_mask[s];
|
||||
}
|
||||
sseu->eu_total = sseu->eu_per_subslice *
|
||||
sseu_subslice_total(sseu);
|
||||
|
||||
|
@ -4427,6 +4487,7 @@ static void i915_print_sseu_info(struct seq_file *m, bool is_available_info,
|
|||
{
|
||||
struct drm_i915_private *dev_priv = node_to_i915(m->private);
|
||||
const char *type = is_available_info ? "Available" : "Enabled";
|
||||
int s;
|
||||
|
||||
seq_printf(m, " %s Slice Mask: %04x\n", type,
|
||||
sseu->slice_mask);
|
||||
|
@ -4434,10 +4495,10 @@ static void i915_print_sseu_info(struct seq_file *m, bool is_available_info,
|
|||
hweight8(sseu->slice_mask));
|
||||
seq_printf(m, " %s Subslice Total: %u\n", type,
|
||||
sseu_subslice_total(sseu));
|
||||
seq_printf(m, " %s Subslice Mask: %04x\n", type,
|
||||
sseu->subslice_mask);
|
||||
seq_printf(m, " %s Subslice Per Slice: %u\n", type,
|
||||
hweight8(sseu->subslice_mask));
|
||||
for (s = 0; s < fls(sseu->slice_mask); s++) {
|
||||
seq_printf(m, " %s Slice%i subslices: %u\n", type,
|
||||
s, hweight8(sseu->subslice_mask[s]));
|
||||
}
|
||||
seq_printf(m, " %s EU Total: %u\n", type,
|
||||
sseu->eu_total);
|
||||
seq_printf(m, " %s EU Per Subslice: %u\n", type,
|
||||
|
@ -4471,6 +4532,10 @@ static int i915_sseu_status(struct seq_file *m, void *unused)
|
|||
|
||||
seq_puts(m, "SSEU Device Status\n");
|
||||
memset(&sseu, 0, sizeof(sseu));
|
||||
sseu.max_slices = INTEL_INFO(dev_priv)->sseu.max_slices;
|
||||
sseu.max_subslices = INTEL_INFO(dev_priv)->sseu.max_subslices;
|
||||
sseu.max_eus_per_subslice =
|
||||
INTEL_INFO(dev_priv)->sseu.max_eus_per_subslice;
|
||||
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
|
@ -4678,6 +4743,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
|
|||
{"i915_dmc_info", i915_dmc_info, 0},
|
||||
{"i915_display_info", i915_display_info, 0},
|
||||
{"i915_engine_info", i915_engine_info, 0},
|
||||
{"i915_rcs_topology", i915_rcs_topology, 0},
|
||||
{"i915_shrinker_info", i915_shrinker_info, 0},
|
||||
{"i915_shared_dplls_info", i915_shared_dplls_info, 0},
|
||||
{"i915_dp_mst_info", i915_dp_mst_info, 0},
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "i915_drv.h"
|
||||
#include "i915_trace.h"
|
||||
#include "i915_pmu.h"
|
||||
#include "i915_query.h"
|
||||
#include "i915_vgpu.h"
|
||||
#include "intel_drv.h"
|
||||
#include "intel_uc.h"
|
||||
|
@ -428,7 +429,7 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data,
|
|||
return -ENODEV;
|
||||
break;
|
||||
case I915_PARAM_SUBSLICE_MASK:
|
||||
value = INTEL_INFO(dev_priv)->sseu.subslice_mask;
|
||||
value = INTEL_INFO(dev_priv)->sseu.subslice_mask[0];
|
||||
if (!value)
|
||||
return -ENODEV;
|
||||
break;
|
||||
|
@ -808,7 +809,7 @@ static int i915_workqueues_init(struct drm_i915_private *dev_priv)
|
|||
/*
|
||||
* The i915 workqueue is primarily used for batched retirement of
|
||||
* requests (and thus managing bo) once the task has been completed
|
||||
* by the GPU. i915_gem_retire_requests() is called directly when we
|
||||
* by the GPU. i915_retire_requests() is called directly when we
|
||||
* need high-priority retirement, such as waiting for an explicit
|
||||
* bo.
|
||||
*
|
||||
|
@ -1992,7 +1993,7 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags)
|
|||
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
|
||||
error:
|
||||
i915_gem_set_wedged(i915);
|
||||
i915_gem_retire_requests(i915);
|
||||
i915_retire_requests(i915);
|
||||
intel_gpu_reset(i915, ALL_ENGINES);
|
||||
goto finish;
|
||||
}
|
||||
|
@ -2019,7 +2020,7 @@ static inline int intel_gt_reset_engine(struct drm_i915_private *dev_priv,
|
|||
int i915_reset_engine(struct intel_engine_cs *engine, unsigned int flags)
|
||||
{
|
||||
struct i915_gpu_error *error = &engine->i915->gpu_error;
|
||||
struct drm_i915_gem_request *active_request;
|
||||
struct i915_request *active_request;
|
||||
int ret;
|
||||
|
||||
GEM_BUG_ON(!test_bit(I915_RESET_ENGINE + engine->id, &error->flags));
|
||||
|
@ -2575,7 +2576,7 @@ static int intel_runtime_suspend(struct device *kdev)
|
|||
*/
|
||||
i915_gem_runtime_suspend(dev_priv);
|
||||
|
||||
intel_guc_suspend(dev_priv);
|
||||
intel_uc_suspend(dev_priv);
|
||||
|
||||
intel_runtime_pm_disable_interrupts(dev_priv);
|
||||
|
||||
|
@ -2597,7 +2598,7 @@ static int intel_runtime_suspend(struct device *kdev)
|
|||
|
||||
intel_runtime_pm_enable_interrupts(dev_priv);
|
||||
|
||||
intel_guc_resume(dev_priv);
|
||||
intel_uc_resume(dev_priv);
|
||||
|
||||
i915_gem_init_swizzling(dev_priv);
|
||||
i915_gem_restore_fences(dev_priv);
|
||||
|
@ -2683,7 +2684,7 @@ static int intel_runtime_resume(struct device *kdev)
|
|||
|
||||
intel_runtime_pm_enable_interrupts(dev_priv);
|
||||
|
||||
intel_guc_resume(dev_priv);
|
||||
intel_uc_resume(dev_priv);
|
||||
|
||||
/*
|
||||
* No point of rolling back things in case of an error, as the best
|
||||
|
@ -2832,6 +2833,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
|
|||
DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, i915_perf_remove_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(I915_QUERY, i915_query_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
|
|
|
@ -71,9 +71,9 @@
|
|||
#include "i915_gem_fence_reg.h"
|
||||
#include "i915_gem_object.h"
|
||||
#include "i915_gem_gtt.h"
|
||||
#include "i915_gem_request.h"
|
||||
#include "i915_gem_timeline.h"
|
||||
|
||||
#include "i915_request.h"
|
||||
#include "i915_vma.h"
|
||||
|
||||
#include "intel_gvt.h"
|
||||
|
@ -83,8 +83,8 @@
|
|||
|
||||
#define DRIVER_NAME "i915"
|
||||
#define DRIVER_DESC "Intel Graphics"
|
||||
#define DRIVER_DATE "20180221"
|
||||
#define DRIVER_TIMESTAMP 1519219289
|
||||
#define DRIVER_DATE "20180308"
|
||||
#define DRIVER_TIMESTAMP 1520513379
|
||||
|
||||
/* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
|
||||
* WARN_ON()) for hw state sanity checks to check for unexpected conditions
|
||||
|
@ -1231,7 +1231,7 @@ struct i915_gpu_error {
|
|||
*
|
||||
* #I915_WEDGED - If reset fails and we can no longer use the GPU,
|
||||
* we set the #I915_WEDGED bit. Prior to command submission, e.g.
|
||||
* i915_gem_request_alloc(), this bit is checked and the sequence
|
||||
* i915_request_alloc(), this bit is checked and the sequence
|
||||
* aborted (with -EIO reported to userspace) if set.
|
||||
*/
|
||||
unsigned long flags;
|
||||
|
@ -2103,6 +2103,7 @@ struct drm_i915_private {
|
|||
*/
|
||||
struct ida hw_ida;
|
||||
#define MAX_CONTEXT_HW_ID (1<<21) /* exclusive */
|
||||
#define GEN11_MAX_CONTEXT_HW_ID (1<<11) /* exclusive */
|
||||
} contexts;
|
||||
|
||||
u32 fdi_rx_config;
|
||||
|
@ -2746,6 +2747,9 @@ intel_info(const struct drm_i915_private *dev_priv)
|
|||
#define BLT_RING ENGINE_MASK(BCS)
|
||||
#define VEBOX_RING ENGINE_MASK(VECS)
|
||||
#define BSD2_RING ENGINE_MASK(VCS2)
|
||||
#define BSD3_RING ENGINE_MASK(VCS3)
|
||||
#define BSD4_RING ENGINE_MASK(VCS4)
|
||||
#define VEBOX2_RING ENGINE_MASK(VECS2)
|
||||
#define ALL_ENGINES (~0)
|
||||
|
||||
#define HAS_ENGINE(dev_priv, id) \
|
||||
|
@ -2768,6 +2772,8 @@ intel_info(const struct drm_i915_private *dev_priv)
|
|||
|
||||
#define HAS_LOGICAL_RING_CONTEXTS(dev_priv) \
|
||||
((dev_priv)->info.has_logical_ring_contexts)
|
||||
#define HAS_LOGICAL_RING_ELSQ(dev_priv) \
|
||||
((dev_priv)->info.has_logical_ring_elsq)
|
||||
#define HAS_LOGICAL_RING_PREEMPTION(dev_priv) \
|
||||
((dev_priv)->info.has_logical_ring_preemption)
|
||||
|
||||
|
@ -2788,9 +2794,10 @@ intel_info(const struct drm_i915_private *dev_priv)
|
|||
/* Early gen2 have a totally busted CS tlb and require pinned batches. */
|
||||
#define HAS_BROKEN_CS_TLB(dev_priv) (IS_I830(dev_priv) || IS_I845G(dev_priv))
|
||||
|
||||
/* WaRsDisableCoarsePowerGating:skl,bxt */
|
||||
/* WaRsDisableCoarsePowerGating:skl,cnl */
|
||||
#define NEEDS_WaRsDisableCoarsePowerGating(dev_priv) \
|
||||
(IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv))
|
||||
(IS_CANNONLAKE(dev_priv) || \
|
||||
IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv))
|
||||
|
||||
/*
|
||||
* dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts
|
||||
|
@ -3329,7 +3336,7 @@ i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj)
|
|||
|
||||
int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
|
||||
void i915_vma_move_to_active(struct i915_vma *vma,
|
||||
struct drm_i915_gem_request *req,
|
||||
struct i915_request *rq,
|
||||
unsigned int flags);
|
||||
int i915_gem_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
|
@ -3344,11 +3351,9 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
|
|||
|
||||
int __must_check i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno);
|
||||
|
||||
struct drm_i915_gem_request *
|
||||
struct i915_request *
|
||||
i915_gem_find_active_request(struct intel_engine_cs *engine);
|
||||
|
||||
void i915_gem_retire_requests(struct drm_i915_private *dev_priv);
|
||||
|
||||
static inline bool i915_reset_backoff(struct i915_gpu_error *error)
|
||||
{
|
||||
return unlikely(test_bit(I915_RESET_BACKOFF, &error->flags));
|
||||
|
@ -3380,7 +3385,7 @@ static inline u32 i915_reset_engine_count(struct i915_gpu_error *error,
|
|||
return READ_ONCE(error->reset_engine_count[engine->id]);
|
||||
}
|
||||
|
||||
struct drm_i915_gem_request *
|
||||
struct i915_request *
|
||||
i915_gem_reset_prepare_engine(struct intel_engine_cs *engine);
|
||||
int i915_gem_reset_prepare(struct drm_i915_private *dev_priv);
|
||||
void i915_gem_reset(struct drm_i915_private *dev_priv);
|
||||
|
@ -3389,7 +3394,7 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv);
|
|||
void i915_gem_set_wedged(struct drm_i915_private *dev_priv);
|
||||
bool i915_gem_unset_wedged(struct drm_i915_private *dev_priv);
|
||||
void i915_gem_reset_engine(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request);
|
||||
struct i915_request *request);
|
||||
|
||||
void i915_gem_init_mmio(struct drm_i915_private *i915);
|
||||
int __must_check i915_gem_init(struct drm_i915_private *dev_priv);
|
||||
|
@ -4008,9 +4013,9 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
|
|||
}
|
||||
|
||||
static inline bool
|
||||
__i915_request_irq_complete(const struct drm_i915_gem_request *req)
|
||||
__i915_request_irq_complete(const struct i915_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
u32 seqno;
|
||||
|
||||
/* Note that the engine may have wrapped around the seqno, and
|
||||
|
@ -4019,7 +4024,7 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req)
|
|||
* this by kicking all the waiters before resetting the seqno
|
||||
* in hardware, and also signal the fence.
|
||||
*/
|
||||
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &req->fence.flags))
|
||||
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
|
||||
return true;
|
||||
|
||||
/* The request was dequeued before we were awoken. We check after
|
||||
|
@ -4028,14 +4033,14 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req)
|
|||
* the request execution are sufficient to ensure that a check
|
||||
* after reading the value from hw matches this request.
|
||||
*/
|
||||
seqno = i915_gem_request_global_seqno(req);
|
||||
seqno = i915_request_global_seqno(rq);
|
||||
if (!seqno)
|
||||
return false;
|
||||
|
||||
/* Before we do the heavier coherent read of the seqno,
|
||||
* check the value (hopefully) in the CPU cacheline.
|
||||
*/
|
||||
if (__i915_gem_request_completed(req, seqno))
|
||||
if (__i915_request_completed(rq, seqno))
|
||||
return true;
|
||||
|
||||
/* Ensure our read of the seqno is coherent so that we
|
||||
|
@ -4084,7 +4089,7 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req)
|
|||
wake_up_process(b->irq_wait->tsk);
|
||||
spin_unlock_irq(&b->irq_lock);
|
||||
|
||||
if (__i915_gem_request_completed(req, seqno))
|
||||
if (__i915_request_completed(rq, seqno))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -353,7 +353,7 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
|
|||
long timeout,
|
||||
struct intel_rps_client *rps_client)
|
||||
{
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
|
||||
BUILD_BUG_ON(I915_WAIT_INTERRUPTIBLE != 0x1);
|
||||
|
||||
|
@ -366,7 +366,7 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
|
|||
timeout);
|
||||
|
||||
rq = to_request(fence);
|
||||
if (i915_gem_request_completed(rq))
|
||||
if (i915_request_completed(rq))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
|
@ -385,16 +385,16 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
|
|||
* forcing the clocks too high for the whole system, we only allow
|
||||
* each client to waitboost once in a busy period.
|
||||
*/
|
||||
if (rps_client && !i915_gem_request_started(rq)) {
|
||||
if (rps_client && !i915_request_started(rq)) {
|
||||
if (INTEL_GEN(rq->i915) >= 6)
|
||||
gen6_rps_boost(rq, rps_client);
|
||||
}
|
||||
|
||||
timeout = i915_wait_request(rq, flags, timeout);
|
||||
timeout = i915_request_wait(rq, flags, timeout);
|
||||
|
||||
out:
|
||||
if (flags & I915_WAIT_LOCKED && i915_gem_request_completed(rq))
|
||||
i915_gem_request_retire_upto(rq);
|
||||
if (flags & I915_WAIT_LOCKED && i915_request_completed(rq))
|
||||
i915_request_retire_upto(rq);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
@ -463,7 +463,7 @@ i915_gem_object_wait_reservation(struct reservation_object *resv,
|
|||
|
||||
static void __fence_set_priority(struct dma_fence *fence, int prio)
|
||||
{
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct intel_engine_cs *engine;
|
||||
|
||||
if (dma_fence_is_signaled(fence) || !dma_fence_is_i915(fence))
|
||||
|
@ -2856,10 +2856,10 @@ static void i915_gem_context_mark_innocent(struct i915_gem_context *ctx)
|
|||
atomic_inc(&ctx->active_count);
|
||||
}
|
||||
|
||||
struct drm_i915_gem_request *
|
||||
struct i915_request *
|
||||
i915_gem_find_active_request(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *request, *active = NULL;
|
||||
struct i915_request *request, *active = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
/* We are called by the error capture and reset at a random
|
||||
|
@ -2872,8 +2872,7 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
|
|||
*/
|
||||
spin_lock_irqsave(&engine->timeline->lock, flags);
|
||||
list_for_each_entry(request, &engine->timeline->requests, link) {
|
||||
if (__i915_gem_request_completed(request,
|
||||
request->global_seqno))
|
||||
if (__i915_request_completed(request, request->global_seqno))
|
||||
continue;
|
||||
|
||||
GEM_BUG_ON(request->engine != engine);
|
||||
|
@ -2906,10 +2905,10 @@ static bool engine_stalled(struct intel_engine_cs *engine)
|
|||
* Ensure irq handler finishes, and not run again.
|
||||
* Also return the active request so that we only search for it once.
|
||||
*/
|
||||
struct drm_i915_gem_request *
|
||||
struct i915_request *
|
||||
i915_gem_reset_prepare_engine(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *request = NULL;
|
||||
struct i915_request *request = NULL;
|
||||
|
||||
/*
|
||||
* During the reset sequence, we must prevent the engine from
|
||||
|
@ -2967,7 +2966,7 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs *engine)
|
|||
int i915_gem_reset_prepare(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
enum intel_engine_id id;
|
||||
int err = 0;
|
||||
|
||||
|
@ -2986,7 +2985,7 @@ int i915_gem_reset_prepare(struct drm_i915_private *dev_priv)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void skip_request(struct drm_i915_gem_request *request)
|
||||
static void skip_request(struct i915_request *request)
|
||||
{
|
||||
void *vaddr = request->ring->vaddr;
|
||||
u32 head;
|
||||
|
@ -3005,7 +3004,7 @@ static void skip_request(struct drm_i915_gem_request *request)
|
|||
dma_fence_set_error(&request->fence, -EIO);
|
||||
}
|
||||
|
||||
static void engine_skip_context(struct drm_i915_gem_request *request)
|
||||
static void engine_skip_context(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct i915_gem_context *hung_ctx = request->ctx;
|
||||
|
@ -3029,9 +3028,9 @@ static void engine_skip_context(struct drm_i915_gem_request *request)
|
|||
}
|
||||
|
||||
/* Returns the request if it was guilty of the hang */
|
||||
static struct drm_i915_gem_request *
|
||||
static struct i915_request *
|
||||
i915_gem_reset_request(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request)
|
||||
struct i915_request *request)
|
||||
{
|
||||
/* The guilty request will get skipped on a hung engine.
|
||||
*
|
||||
|
@ -3085,7 +3084,7 @@ i915_gem_reset_request(struct intel_engine_cs *engine,
|
|||
}
|
||||
|
||||
void i915_gem_reset_engine(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request)
|
||||
struct i915_request *request)
|
||||
{
|
||||
/*
|
||||
* Make sure this write is visible before we re-enable the interrupt
|
||||
|
@ -3113,7 +3112,7 @@ void i915_gem_reset(struct drm_i915_private *dev_priv)
|
|||
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
i915_retire_requests(dev_priv);
|
||||
|
||||
for_each_engine(engine, dev_priv, id) {
|
||||
struct i915_gem_context *ctx;
|
||||
|
@ -3134,12 +3133,12 @@ void i915_gem_reset(struct drm_i915_private *dev_priv)
|
|||
* empty request appears sufficient to paper over the glitch.
|
||||
*/
|
||||
if (intel_engine_is_idle(engine)) {
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
|
||||
rq = i915_gem_request_alloc(engine,
|
||||
dev_priv->kernel_context);
|
||||
rq = i915_request_alloc(engine,
|
||||
dev_priv->kernel_context);
|
||||
if (!IS_ERR(rq))
|
||||
__i915_add_request(rq, false);
|
||||
__i915_request_add(rq, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3174,21 +3173,21 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv)
|
|||
}
|
||||
}
|
||||
|
||||
static void nop_submit_request(struct drm_i915_gem_request *request)
|
||||
static void nop_submit_request(struct i915_request *request)
|
||||
{
|
||||
dma_fence_set_error(&request->fence, -EIO);
|
||||
|
||||
i915_gem_request_submit(request);
|
||||
i915_request_submit(request);
|
||||
}
|
||||
|
||||
static void nop_complete_submit_request(struct drm_i915_gem_request *request)
|
||||
static void nop_complete_submit_request(struct i915_request *request)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dma_fence_set_error(&request->fence, -EIO);
|
||||
|
||||
spin_lock_irqsave(&request->engine->timeline->lock, flags);
|
||||
__i915_gem_request_submit(request);
|
||||
__i915_request_submit(request);
|
||||
intel_engine_init_global_seqno(request->engine, request->global_seqno);
|
||||
spin_unlock_irqrestore(&request->engine->timeline->lock, flags);
|
||||
}
|
||||
|
@ -3213,8 +3212,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
|
|||
* rolling the global seqno forward (since this would complete requests
|
||||
* for which we haven't set the fence error to EIO yet).
|
||||
*/
|
||||
for_each_engine(engine, i915, id)
|
||||
for_each_engine(engine, i915, id) {
|
||||
i915_gem_reset_prepare_engine(engine);
|
||||
engine->submit_request = nop_submit_request;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure no one is running the old callback before we proceed with
|
||||
|
@ -3256,6 +3257,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
|
|||
intel_engine_init_global_seqno(engine,
|
||||
intel_engine_last_submit(engine));
|
||||
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
||||
|
||||
i915_gem_reset_finish_engine(engine);
|
||||
}
|
||||
|
||||
wake_up_all(&i915->gpu_error.reset_queue);
|
||||
|
@ -3281,7 +3284,7 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
|
|||
*/
|
||||
list_for_each_entry(tl, &i915->gt.timelines, link) {
|
||||
for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
|
||||
rq = i915_gem_active_peek(&tl->engine[i].last_request,
|
||||
&i915->drm.struct_mutex);
|
||||
|
@ -3330,7 +3333,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
|
|||
|
||||
/* Come back later if the device is busy... */
|
||||
if (mutex_trylock(&dev->struct_mutex)) {
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
i915_retire_requests(dev_priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
|
@ -3418,25 +3421,22 @@ i915_gem_idle_work_handler(struct work_struct *work)
|
|||
container_of(work, typeof(*dev_priv), gt.idle_work.work);
|
||||
unsigned int epoch = I915_EPOCH_INVALID;
|
||||
bool rearm_hangcheck;
|
||||
ktime_t end;
|
||||
|
||||
if (!READ_ONCE(dev_priv->gt.awake))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Wait for last execlists context complete, but bail out in case a
|
||||
* new request is submitted.
|
||||
* new request is submitted. As we don't trust the hardware, we
|
||||
* continue on if the wait times out. This is necessary to allow
|
||||
* the machine to suspend even if the hardware dies, and we will
|
||||
* try to recover in resume (after depriving the hardware of power,
|
||||
* it may be in a better mmod).
|
||||
*/
|
||||
end = ktime_add_ms(ktime_get(), I915_IDLE_ENGINES_TIMEOUT);
|
||||
do {
|
||||
if (new_requests_since_last_retire(dev_priv))
|
||||
return;
|
||||
|
||||
if (intel_engines_are_idle(dev_priv))
|
||||
break;
|
||||
|
||||
usleep_range(100, 500);
|
||||
} while (ktime_before(ktime_get(), end));
|
||||
__wait_for(if (new_requests_since_last_retire(dev_priv)) return,
|
||||
intel_engines_are_idle(dev_priv),
|
||||
I915_IDLE_ENGINES_TIMEOUT * 1000,
|
||||
10, 500);
|
||||
|
||||
rearm_hangcheck =
|
||||
cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
|
||||
|
@ -3684,7 +3684,7 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
|
|||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
i915_gem_retire_requests(i915);
|
||||
i915_retire_requests(i915);
|
||||
|
||||
ret = wait_for_engines(i915);
|
||||
} else {
|
||||
|
@ -4224,7 +4224,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
|
|||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_file_private *file_priv = file->driver_priv;
|
||||
unsigned long recent_enough = jiffies - DRM_I915_THROTTLE_JIFFIES;
|
||||
struct drm_i915_gem_request *request, *target = NULL;
|
||||
struct i915_request *request, *target = NULL;
|
||||
long ret;
|
||||
|
||||
/* ABI: return -EIO if already wedged */
|
||||
|
@ -4244,16 +4244,16 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
|
|||
target = request;
|
||||
}
|
||||
if (target)
|
||||
i915_gem_request_get(target);
|
||||
i915_request_get(target);
|
||||
spin_unlock(&file_priv->mm.lock);
|
||||
|
||||
if (target == NULL)
|
||||
return 0;
|
||||
|
||||
ret = i915_wait_request(target,
|
||||
ret = i915_request_wait(target,
|
||||
I915_WAIT_INTERRUPTIBLE,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
i915_gem_request_put(target);
|
||||
i915_request_put(target);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
@ -4367,7 +4367,7 @@ static __always_inline unsigned int
|
|||
__busy_set_if_active(const struct dma_fence *fence,
|
||||
unsigned int (*flag)(unsigned int id))
|
||||
{
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
|
||||
/* We have to check the current hw status of the fence as the uABI
|
||||
* guarantees forward progress. We could rely on the idle worker
|
||||
|
@ -4380,8 +4380,8 @@ __busy_set_if_active(const struct dma_fence *fence,
|
|||
return 0;
|
||||
|
||||
/* opencode to_request() in order to avoid const warnings */
|
||||
rq = container_of(fence, struct drm_i915_gem_request, fence);
|
||||
if (i915_gem_request_completed(rq))
|
||||
rq = container_of(fence, struct i915_request, fence);
|
||||
if (i915_request_completed(rq))
|
||||
return 0;
|
||||
|
||||
return flag(rq->engine->uabi_id);
|
||||
|
@ -4526,8 +4526,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
static void
|
||||
frontbuffer_retire(struct i915_gem_active *active,
|
||||
struct drm_i915_gem_request *request)
|
||||
frontbuffer_retire(struct i915_gem_active *active, struct i915_request *request)
|
||||
{
|
||||
struct drm_i915_gem_object *obj =
|
||||
container_of(active, typeof(*obj), frontbuffer_write);
|
||||
|
@ -4921,7 +4920,7 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv)
|
|||
i915_gem_contexts_lost(dev_priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
intel_guc_suspend(dev_priv);
|
||||
intel_uc_suspend(dev_priv);
|
||||
|
||||
cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
|
||||
cancel_delayed_work_sync(&dev_priv->gt.retire_work);
|
||||
|
@ -4988,7 +4987,7 @@ void i915_gem_resume(struct drm_i915_private *i915)
|
|||
if (i915_gem_init_hw(i915))
|
||||
goto err_wedged;
|
||||
|
||||
intel_guc_resume(i915);
|
||||
intel_uc_resume(i915);
|
||||
|
||||
/* Always reload a context for powersaving. */
|
||||
if (i915_gem_switch_to_kernel_context(i915))
|
||||
|
@ -5161,9 +5160,9 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
|
|||
return PTR_ERR(ctx);
|
||||
|
||||
for_each_engine(engine, i915, id) {
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
|
||||
rq = i915_gem_request_alloc(engine, ctx);
|
||||
rq = i915_request_alloc(engine, ctx);
|
||||
if (IS_ERR(rq)) {
|
||||
err = PTR_ERR(rq);
|
||||
goto out_ctx;
|
||||
|
@ -5173,7 +5172,7 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
|
|||
if (engine->init_context)
|
||||
err = engine->init_context(rq);
|
||||
|
||||
__i915_add_request(rq, true);
|
||||
__i915_request_add(rq, true);
|
||||
if (err)
|
||||
goto err_active;
|
||||
}
|
||||
|
@ -5479,7 +5478,7 @@ i915_gem_load_init(struct drm_i915_private *dev_priv)
|
|||
if (!dev_priv->luts)
|
||||
goto err_vmas;
|
||||
|
||||
dev_priv->requests = KMEM_CACHE(drm_i915_gem_request,
|
||||
dev_priv->requests = KMEM_CACHE(i915_request,
|
||||
SLAB_HWCACHE_ALIGN |
|
||||
SLAB_RECLAIM_ACCOUNT |
|
||||
SLAB_TYPESAFE_BY_RCU);
|
||||
|
@ -5612,7 +5611,7 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv)
|
|||
void i915_gem_release(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct drm_i915_file_private *file_priv = file->driver_priv;
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
|
||||
/* Clean up our request list when the client is going away, so that
|
||||
* later retire_requests won't dereference our soon-to-be-gone
|
||||
|
|
|
@ -29,7 +29,10 @@
|
|||
|
||||
#ifdef CONFIG_DRM_I915_DEBUG_GEM
|
||||
#define GEM_BUG_ON(condition) do { if (unlikely((condition))) { \
|
||||
printk(KERN_ERR "GEM_BUG_ON(%s)\n", __stringify(condition)); \
|
||||
pr_err("%s:%d GEM_BUG_ON(%s)\n", \
|
||||
__func__, __LINE__, __stringify(condition)); \
|
||||
GEM_TRACE("%s:%d GEM_BUG_ON(%s)\n", \
|
||||
__func__, __LINE__, __stringify(condition)); \
|
||||
BUG(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
@ -54,6 +57,6 @@
|
|||
#define GEM_TRACE(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define I915_NUM_ENGINES 5
|
||||
#define I915_NUM_ENGINES 8
|
||||
|
||||
#endif /* __I915_GEM_H__ */
|
||||
|
|
|
@ -119,7 +119,7 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
|
|||
if (!reservation_object_test_signaled_rcu(resv, true))
|
||||
break;
|
||||
|
||||
i915_gem_retire_requests(pool->engine->i915);
|
||||
i915_retire_requests(pool->engine->i915);
|
||||
GEM_BUG_ON(i915_gem_object_is_active(obj));
|
||||
|
||||
/*
|
||||
|
|
|
@ -211,17 +211,23 @@ static void context_close(struct i915_gem_context *ctx)
|
|||
static int assign_hw_id(struct drm_i915_private *dev_priv, unsigned *out)
|
||||
{
|
||||
int ret;
|
||||
unsigned int max;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 11)
|
||||
max = GEN11_MAX_CONTEXT_HW_ID;
|
||||
else
|
||||
max = MAX_CONTEXT_HW_ID;
|
||||
|
||||
ret = ida_simple_get(&dev_priv->contexts.hw_ida,
|
||||
0, MAX_CONTEXT_HW_ID, GFP_KERNEL);
|
||||
0, max, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
/* Contexts are only released when no longer active.
|
||||
* Flush any pending retires to hopefully release some
|
||||
* stale contexts and try again.
|
||||
*/
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
i915_retire_requests(dev_priv);
|
||||
ret = ida_simple_get(&dev_priv->contexts.hw_ida,
|
||||
0, MAX_CONTEXT_HW_ID, GFP_KERNEL);
|
||||
0, max, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -463,6 +469,7 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
|
|||
|
||||
/* Using the simple ida interface, the max is limited by sizeof(int) */
|
||||
BUILD_BUG_ON(MAX_CONTEXT_HW_ID > INT_MAX);
|
||||
BUILD_BUG_ON(GEN11_MAX_CONTEXT_HW_ID > INT_MAX);
|
||||
ida_init(&dev_priv->contexts.hw_ida);
|
||||
|
||||
/* lowest priority; idle task */
|
||||
|
@ -590,28 +597,28 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
|
|||
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
i915_retire_requests(dev_priv);
|
||||
|
||||
for_each_engine(engine, dev_priv, id) {
|
||||
struct drm_i915_gem_request *req;
|
||||
struct i915_request *rq;
|
||||
|
||||
if (engine_has_idle_kernel_context(engine))
|
||||
continue;
|
||||
|
||||
req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
rq = i915_request_alloc(engine, dev_priv->kernel_context);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
/* Queue this switch after all other activity */
|
||||
list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
|
||||
struct drm_i915_gem_request *prev;
|
||||
struct i915_request *prev;
|
||||
struct intel_timeline *tl;
|
||||
|
||||
tl = &timeline->engine[engine->id];
|
||||
prev = i915_gem_active_raw(&tl->last_request,
|
||||
&dev_priv->drm.struct_mutex);
|
||||
if (prev)
|
||||
i915_sw_fence_await_sw_fence_gfp(&req->submit,
|
||||
i915_sw_fence_await_sw_fence_gfp(&rq->submit,
|
||||
&prev->submit,
|
||||
I915_FENCE_GFP);
|
||||
}
|
||||
|
@ -623,7 +630,7 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
|
|||
* but an extra layer of paranoia before we declare the system
|
||||
* idle (on suspend etc) is advisable!
|
||||
*/
|
||||
__i915_add_request(req, true);
|
||||
__i915_request_add(rq, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -38,8 +38,8 @@ struct drm_file;
|
|||
|
||||
struct drm_i915_private;
|
||||
struct drm_i915_file_private;
|
||||
struct drm_i915_gem_request;
|
||||
struct i915_hw_ppgtt;
|
||||
struct i915_request;
|
||||
struct i915_vma;
|
||||
struct intel_ring;
|
||||
|
||||
|
@ -276,7 +276,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
|
|||
struct drm_file *file);
|
||||
void i915_gem_context_close(struct drm_file *file);
|
||||
|
||||
int i915_switch_context(struct drm_i915_gem_request *req);
|
||||
int i915_switch_context(struct i915_request *rq);
|
||||
int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv);
|
||||
|
||||
void i915_gem_context_release(struct kref *ctx_ref);
|
||||
|
|
|
@ -168,7 +168,7 @@ i915_gem_evict_something(struct i915_address_space *vm,
|
|||
* retiring.
|
||||
*/
|
||||
if (!(flags & PIN_NONBLOCK))
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
i915_retire_requests(dev_priv);
|
||||
else
|
||||
phases[1] = NULL;
|
||||
|
||||
|
@ -293,7 +293,7 @@ int i915_gem_evict_for_node(struct i915_address_space *vm,
|
|||
* retiring.
|
||||
*/
|
||||
if (!(flags & PIN_NONBLOCK))
|
||||
i915_gem_retire_requests(vm->i915);
|
||||
i915_retire_requests(vm->i915);
|
||||
|
||||
check_color = vm->mm.color_adjust;
|
||||
if (check_color) {
|
||||
|
|
|
@ -200,7 +200,7 @@ struct i915_execbuffer {
|
|||
struct i915_gem_context *ctx; /** context for building the request */
|
||||
struct i915_address_space *vm; /** GTT and vma for the request */
|
||||
|
||||
struct drm_i915_gem_request *request; /** our request to build */
|
||||
struct i915_request *request; /** our request to build */
|
||||
struct i915_vma *batch; /** identity of the batch obj/vma */
|
||||
|
||||
/** actual size of execobj[] as we may extend it for the cmdparser */
|
||||
|
@ -227,7 +227,7 @@ struct i915_execbuffer {
|
|||
bool has_fence : 1;
|
||||
bool needs_unfenced : 1;
|
||||
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
u32 *rq_cmd;
|
||||
unsigned int rq_size;
|
||||
} reloc_cache;
|
||||
|
@ -886,7 +886,7 @@ static void reloc_gpu_flush(struct reloc_cache *cache)
|
|||
i915_gem_object_unpin_map(cache->rq->batch->obj);
|
||||
i915_gem_chipset_flush(cache->rq->i915);
|
||||
|
||||
__i915_add_request(cache->rq, true);
|
||||
__i915_request_add(cache->rq, true);
|
||||
cache->rq = NULL;
|
||||
}
|
||||
|
||||
|
@ -1070,7 +1070,7 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb,
|
|||
{
|
||||
struct reloc_cache *cache = &eb->reloc_cache;
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct i915_vma *batch;
|
||||
u32 *cmd;
|
||||
int err;
|
||||
|
@ -1103,13 +1103,13 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb,
|
|||
if (err)
|
||||
goto err_unmap;
|
||||
|
||||
rq = i915_gem_request_alloc(eb->engine, eb->ctx);
|
||||
rq = i915_request_alloc(eb->engine, eb->ctx);
|
||||
if (IS_ERR(rq)) {
|
||||
err = PTR_ERR(rq);
|
||||
goto err_unpin;
|
||||
}
|
||||
|
||||
err = i915_gem_request_await_object(rq, vma->obj, true);
|
||||
err = i915_request_await_object(rq, vma->obj, true);
|
||||
if (err)
|
||||
goto err_request;
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb,
|
|||
return 0;
|
||||
|
||||
err_request:
|
||||
i915_add_request(rq);
|
||||
i915_request_add(rq);
|
||||
err_unpin:
|
||||
i915_vma_unpin(batch);
|
||||
err_unmap:
|
||||
|
@ -1727,7 +1727,7 @@ static int eb_relocate(struct i915_execbuffer *eb)
|
|||
}
|
||||
|
||||
static void eb_export_fence(struct i915_vma *vma,
|
||||
struct drm_i915_gem_request *req,
|
||||
struct i915_request *rq,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct reservation_object *resv = vma->resv;
|
||||
|
@ -1739,9 +1739,9 @@ static void eb_export_fence(struct i915_vma *vma,
|
|||
*/
|
||||
reservation_object_lock(resv, NULL);
|
||||
if (flags & EXEC_OBJECT_WRITE)
|
||||
reservation_object_add_excl_fence(resv, &req->fence);
|
||||
reservation_object_add_excl_fence(resv, &rq->fence);
|
||||
else if (reservation_object_reserve_shared(resv) == 0)
|
||||
reservation_object_add_shared_fence(resv, &req->fence);
|
||||
reservation_object_add_shared_fence(resv, &rq->fence);
|
||||
reservation_object_unlock(resv);
|
||||
}
|
||||
|
||||
|
@ -1757,7 +1757,7 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
|
|||
struct drm_i915_gem_object *obj = vma->obj;
|
||||
|
||||
if (flags & EXEC_OBJECT_CAPTURE) {
|
||||
struct i915_gem_capture_list *capture;
|
||||
struct i915_capture_list *capture;
|
||||
|
||||
capture = kmalloc(sizeof(*capture), GFP_KERNEL);
|
||||
if (unlikely(!capture))
|
||||
|
@ -1788,7 +1788,7 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
|
|||
if (flags & EXEC_OBJECT_ASYNC)
|
||||
continue;
|
||||
|
||||
err = i915_gem_request_await_object
|
||||
err = i915_request_await_object
|
||||
(eb->request, obj, flags & EXEC_OBJECT_WRITE);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -1840,13 +1840,13 @@ static bool i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
|
|||
}
|
||||
|
||||
void i915_vma_move_to_active(struct i915_vma *vma,
|
||||
struct drm_i915_gem_request *req,
|
||||
struct i915_request *rq,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct drm_i915_gem_object *obj = vma->obj;
|
||||
const unsigned int idx = req->engine->id;
|
||||
const unsigned int idx = rq->engine->id;
|
||||
|
||||
lockdep_assert_held(&req->i915->drm.struct_mutex);
|
||||
lockdep_assert_held(&rq->i915->drm.struct_mutex);
|
||||
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
|
||||
|
||||
/*
|
||||
|
@ -1860,7 +1860,7 @@ void i915_vma_move_to_active(struct i915_vma *vma,
|
|||
if (!i915_vma_is_active(vma))
|
||||
obj->active_count++;
|
||||
i915_vma_set_active(vma, idx);
|
||||
i915_gem_active_set(&vma->last_read[idx], req);
|
||||
i915_gem_active_set(&vma->last_read[idx], rq);
|
||||
list_move_tail(&vma->vm_link, &vma->vm->active_list);
|
||||
|
||||
obj->write_domain = 0;
|
||||
|
@ -1868,27 +1868,27 @@ void i915_vma_move_to_active(struct i915_vma *vma,
|
|||
obj->write_domain = I915_GEM_DOMAIN_RENDER;
|
||||
|
||||
if (intel_fb_obj_invalidate(obj, ORIGIN_CS))
|
||||
i915_gem_active_set(&obj->frontbuffer_write, req);
|
||||
i915_gem_active_set(&obj->frontbuffer_write, rq);
|
||||
|
||||
obj->read_domains = 0;
|
||||
}
|
||||
obj->read_domains |= I915_GEM_GPU_DOMAINS;
|
||||
|
||||
if (flags & EXEC_OBJECT_NEEDS_FENCE)
|
||||
i915_gem_active_set(&vma->last_fence, req);
|
||||
i915_gem_active_set(&vma->last_fence, rq);
|
||||
}
|
||||
|
||||
static int i915_reset_gen7_sol_offsets(struct drm_i915_gem_request *req)
|
||||
static int i915_reset_gen7_sol_offsets(struct i915_request *rq)
|
||||
{
|
||||
u32 *cs;
|
||||
int i;
|
||||
|
||||
if (!IS_GEN7(req->i915) || req->engine->id != RCS) {
|
||||
if (!IS_GEN7(rq->i915) || rq->engine->id != RCS) {
|
||||
DRM_DEBUG("sol reset is gen7/rcs only\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cs = intel_ring_begin(req, 4 * 2 + 2);
|
||||
cs = intel_ring_begin(rq, 4 * 2 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1898,7 +1898,7 @@ static int i915_reset_gen7_sol_offsets(struct drm_i915_gem_request *req)
|
|||
*cs++ = 0;
|
||||
}
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1944,10 +1944,10 @@ static struct i915_vma *eb_parse(struct i915_execbuffer *eb, bool is_master)
|
|||
}
|
||||
|
||||
static void
|
||||
add_to_client(struct drm_i915_gem_request *req, struct drm_file *file)
|
||||
add_to_client(struct i915_request *rq, struct drm_file *file)
|
||||
{
|
||||
req->file_priv = file->driver_priv;
|
||||
list_add_tail(&req->client_link, &req->file_priv->mm.request_list);
|
||||
rq->file_priv = file->driver_priv;
|
||||
list_add_tail(&rq->client_link, &rq->file_priv->mm.request_list);
|
||||
}
|
||||
|
||||
static int eb_submit(struct i915_execbuffer *eb)
|
||||
|
@ -2151,7 +2151,7 @@ await_fence_array(struct i915_execbuffer *eb,
|
|||
if (!fence)
|
||||
return -EINVAL;
|
||||
|
||||
err = i915_gem_request_await_dma_fence(eb->request, fence);
|
||||
err = i915_request_await_dma_fence(eb->request, fence);
|
||||
dma_fence_put(fence);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -2365,14 +2365,14 @@ i915_gem_do_execbuffer(struct drm_device *dev,
|
|||
GEM_BUG_ON(eb.reloc_cache.rq);
|
||||
|
||||
/* Allocate a request for this batch buffer nice and early. */
|
||||
eb.request = i915_gem_request_alloc(eb.engine, eb.ctx);
|
||||
eb.request = i915_request_alloc(eb.engine, eb.ctx);
|
||||
if (IS_ERR(eb.request)) {
|
||||
err = PTR_ERR(eb.request);
|
||||
goto err_batch_unpin;
|
||||
}
|
||||
|
||||
if (in_fence) {
|
||||
err = i915_gem_request_await_dma_fence(eb.request, in_fence);
|
||||
err = i915_request_await_dma_fence(eb.request, in_fence);
|
||||
if (err < 0)
|
||||
goto err_request;
|
||||
}
|
||||
|
@ -2400,10 +2400,10 @@ i915_gem_do_execbuffer(struct drm_device *dev,
|
|||
*/
|
||||
eb.request->batch = eb.batch;
|
||||
|
||||
trace_i915_gem_request_queue(eb.request, eb.batch_flags);
|
||||
trace_i915_request_queue(eb.request, eb.batch_flags);
|
||||
err = eb_submit(&eb);
|
||||
err_request:
|
||||
__i915_add_request(eb.request, err == 0);
|
||||
__i915_request_add(eb.request, err == 0);
|
||||
add_to_client(eb.request, file);
|
||||
|
||||
if (fences)
|
||||
|
|
|
@ -765,16 +765,16 @@ static void gen8_initialize_pml4(struct i915_address_space *vm,
|
|||
}
|
||||
|
||||
/* Broadwell Page Directory Pointer Descriptors */
|
||||
static int gen8_write_pdp(struct drm_i915_gem_request *req,
|
||||
static int gen8_write_pdp(struct i915_request *rq,
|
||||
unsigned entry,
|
||||
dma_addr_t addr)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
u32 *cs;
|
||||
|
||||
BUG_ON(entry >= 4);
|
||||
|
||||
cs = intel_ring_begin(req, 6);
|
||||
cs = intel_ring_begin(rq, 6);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -784,20 +784,20 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req,
|
|||
*cs++ = MI_LOAD_REGISTER_IMM(1);
|
||||
*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(engine, entry));
|
||||
*cs++ = lower_32_bits(addr);
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen8_mm_switch_3lvl(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_request *req)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = GEN8_3LVL_PDPES - 1; i >= 0; i--) {
|
||||
const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
|
||||
|
||||
ret = gen8_write_pdp(req, i, pd_daddr);
|
||||
ret = gen8_write_pdp(rq, i, pd_daddr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -806,9 +806,9 @@ static int gen8_mm_switch_3lvl(struct i915_hw_ppgtt *ppgtt,
|
|||
}
|
||||
|
||||
static int gen8_mm_switch_4lvl(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_request *req)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
return gen8_write_pdp(req, 0, px_dma(&ppgtt->pml4));
|
||||
return gen8_write_pdp(rq, 0, px_dma(&ppgtt->pml4));
|
||||
}
|
||||
|
||||
/* PDE TLBs are a pain to invalidate on GEN8+. When we modify
|
||||
|
@ -1732,13 +1732,13 @@ static inline u32 get_pd_offset(struct i915_hw_ppgtt *ppgtt)
|
|||
}
|
||||
|
||||
static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_request *req)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
u32 *cs;
|
||||
|
||||
/* NB: TLBs must be flushed and invalidated before a switch */
|
||||
cs = intel_ring_begin(req, 6);
|
||||
cs = intel_ring_begin(rq, 6);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1748,19 +1748,19 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
|||
*cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine));
|
||||
*cs++ = get_pd_offset(ppgtt);
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_request *req)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
u32 *cs;
|
||||
|
||||
/* NB: TLBs must be flushed and invalidated before a switch */
|
||||
cs = intel_ring_begin(req, 6);
|
||||
cs = intel_ring_begin(rq, 6);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1770,16 +1770,16 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
|||
*cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine));
|
||||
*cs++ = get_pd_offset(ppgtt);
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_request *req)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct drm_i915_private *dev_priv = req->i915;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
struct drm_i915_private *dev_priv = rq->i915;
|
||||
|
||||
I915_WRITE(RING_PP_DIR_DCLV(engine), PP_DIR_DCLV_2G);
|
||||
I915_WRITE(RING_PP_DIR_BASE(engine), get_pd_offset(ppgtt));
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
#include <linux/pagevec.h>
|
||||
|
||||
#include "i915_gem_timeline.h"
|
||||
#include "i915_gem_request.h"
|
||||
|
||||
#include "i915_request.h"
|
||||
#include "i915_selftest.h"
|
||||
|
||||
#define I915_GTT_PAGE_SIZE_4K BIT(12)
|
||||
|
@ -398,7 +399,7 @@ struct i915_hw_ppgtt {
|
|||
gen6_pte_t __iomem *pd_addr;
|
||||
|
||||
int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_request *req);
|
||||
struct i915_request *rq);
|
||||
void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
|
||||
};
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#include <drm/i915_drm.h>
|
||||
|
||||
#include "i915_gem_request.h"
|
||||
#include "i915_request.h"
|
||||
#include "i915_selftest.h"
|
||||
|
||||
struct drm_i915_gem_object;
|
||||
|
|
|
@ -177,7 +177,7 @@ static int render_state_setup(struct intel_render_state *so,
|
|||
|
||||
#undef OUT_BATCH
|
||||
|
||||
int i915_gem_render_state_emit(struct drm_i915_gem_request *rq)
|
||||
int i915_gem_render_state_emit(struct i915_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
struct intel_render_state so = {}; /* keep the compiler happy */
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#ifndef _I915_GEM_RENDER_STATE_H_
|
||||
#define _I915_GEM_RENDER_STATE_H_
|
||||
|
||||
struct drm_i915_gem_request;
|
||||
struct i915_request;
|
||||
|
||||
int i915_gem_render_state_emit(struct drm_i915_gem_request *rq);
|
||||
int i915_gem_render_state_emit(struct i915_request *rq);
|
||||
|
||||
#endif /* _I915_GEM_RENDER_STATE_H_ */
|
||||
|
|
|
@ -175,7 +175,7 @@ i915_gem_shrink(struct drm_i915_private *i915,
|
|||
i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
|
||||
|
||||
trace_i915_gem_shrink(i915, target, flags);
|
||||
i915_gem_retire_requests(i915);
|
||||
i915_retire_requests(i915);
|
||||
|
||||
/*
|
||||
* Unbinding of objects will require HW access; Let us not wake the
|
||||
|
@ -267,7 +267,7 @@ i915_gem_shrink(struct drm_i915_private *i915,
|
|||
if (flags & I915_SHRINK_BOUND)
|
||||
intel_runtime_pm_put(i915);
|
||||
|
||||
i915_gem_retire_requests(i915);
|
||||
i915_retire_requests(i915);
|
||||
|
||||
shrinker_unlock(i915, unlock);
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "i915_utils.h"
|
||||
#include "i915_gem_request.h"
|
||||
#include "i915_request.h"
|
||||
#include "i915_syncmap.h"
|
||||
#include "i915_utils.h"
|
||||
|
||||
struct i915_gem_timeline;
|
||||
|
||||
|
|
|
@ -586,6 +586,7 @@ static void err_print_capabilities(struct drm_i915_error_state_buf *m,
|
|||
|
||||
intel_device_info_dump_flags(info, &p);
|
||||
intel_driver_caps_print(caps, &p);
|
||||
intel_device_info_dump_topology(&info->sseu, &p);
|
||||
}
|
||||
|
||||
static void err_print_params(struct drm_i915_error_state_buf *m,
|
||||
|
@ -991,7 +992,7 @@ i915_error_object_create(struct drm_i915_private *i915,
|
|||
static inline uint32_t
|
||||
__active_get_seqno(struct i915_gem_active *active)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
|
||||
request = __i915_gem_active_peek(active);
|
||||
return request ? request->global_seqno : 0;
|
||||
|
@ -1000,7 +1001,7 @@ __active_get_seqno(struct i915_gem_active *active)
|
|||
static inline int
|
||||
__active_get_engine_id(struct i915_gem_active *active)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
|
||||
request = __i915_gem_active_peek(active);
|
||||
return request ? request->engine->id : -1;
|
||||
|
@ -1084,9 +1085,9 @@ static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv,
|
|||
return error_code;
|
||||
}
|
||||
|
||||
static void i915_gem_record_fences(struct drm_i915_private *dev_priv,
|
||||
struct i915_gpu_state *error)
|
||||
static void gem_record_fences(struct i915_gpu_state *error)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = error->i915;
|
||||
int i;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 6) {
|
||||
|
@ -1102,27 +1103,6 @@ static void i915_gem_record_fences(struct drm_i915_private *dev_priv,
|
|||
error->nfence = i;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
gen8_engine_sync_index(struct intel_engine_cs *engine,
|
||||
struct intel_engine_cs *other)
|
||||
{
|
||||
int idx;
|
||||
|
||||
/*
|
||||
* rcs -> 0 = vcs, 1 = bcs, 2 = vecs, 3 = vcs2;
|
||||
* vcs -> 0 = bcs, 1 = vecs, 2 = vcs2, 3 = rcs;
|
||||
* bcs -> 0 = vecs, 1 = vcs2. 2 = rcs, 3 = vcs;
|
||||
* vecs -> 0 = vcs2, 1 = rcs, 2 = vcs, 3 = bcs;
|
||||
* vcs2 -> 0 = rcs, 1 = vcs, 2 = bcs, 3 = vecs;
|
||||
*/
|
||||
|
||||
idx = (other - engine) - 1;
|
||||
if (idx < 0)
|
||||
idx += I915_NUM_ENGINES;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void gen6_record_semaphore_state(struct intel_engine_cs *engine,
|
||||
struct drm_i915_error_engine *ee)
|
||||
{
|
||||
|
@ -1293,7 +1273,7 @@ static void error_record_engine_registers(struct i915_gpu_state *error,
|
|||
}
|
||||
}
|
||||
|
||||
static void record_request(struct drm_i915_gem_request *request,
|
||||
static void record_request(struct i915_request *request,
|
||||
struct drm_i915_error_request *erq)
|
||||
{
|
||||
erq->context = request->ctx->hw_id;
|
||||
|
@ -1310,10 +1290,10 @@ static void record_request(struct drm_i915_gem_request *request,
|
|||
}
|
||||
|
||||
static void engine_record_requests(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *first,
|
||||
struct i915_request *first,
|
||||
struct drm_i915_error_engine *ee)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
@ -1363,7 +1343,7 @@ static void error_record_engine_execlists(struct intel_engine_cs *engine,
|
|||
unsigned int n;
|
||||
|
||||
for (n = 0; n < execlists_num_ports(execlists); n++) {
|
||||
struct drm_i915_gem_request *rq = port_request(&execlists->port[n]);
|
||||
struct i915_request *rq = port_request(&execlists->port[n]);
|
||||
|
||||
if (!rq)
|
||||
break;
|
||||
|
@ -1398,10 +1378,10 @@ static void record_context(struct drm_i915_error_context *e,
|
|||
e->active = atomic_read(&ctx->active_count);
|
||||
}
|
||||
|
||||
static void request_record_user_bo(struct drm_i915_gem_request *request,
|
||||
static void request_record_user_bo(struct i915_request *request,
|
||||
struct drm_i915_error_engine *ee)
|
||||
{
|
||||
struct i915_gem_capture_list *c;
|
||||
struct i915_capture_list *c;
|
||||
struct drm_i915_error_object **bo;
|
||||
long count;
|
||||
|
||||
|
@ -1445,16 +1425,16 @@ capture_object(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
}
|
||||
|
||||
static void i915_gem_record_rings(struct drm_i915_private *dev_priv,
|
||||
struct i915_gpu_state *error)
|
||||
static void gem_record_rings(struct i915_gpu_state *error)
|
||||
{
|
||||
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
||||
struct drm_i915_private *i915 = error->i915;
|
||||
struct i915_ggtt *ggtt = &i915->ggtt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I915_NUM_ENGINES; i++) {
|
||||
struct intel_engine_cs *engine = dev_priv->engine[i];
|
||||
struct intel_engine_cs *engine = i915->engine[i];
|
||||
struct drm_i915_error_engine *ee = &error->engine[i];
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
|
||||
ee->engine_id = -1;
|
||||
|
||||
|
@ -1481,17 +1461,16 @@ static void i915_gem_record_rings(struct drm_i915_private *dev_priv,
|
|||
* by userspace.
|
||||
*/
|
||||
ee->batchbuffer =
|
||||
i915_error_object_create(dev_priv,
|
||||
request->batch);
|
||||
i915_error_object_create(i915, request->batch);
|
||||
|
||||
if (HAS_BROKEN_CS_TLB(dev_priv))
|
||||
if (HAS_BROKEN_CS_TLB(i915))
|
||||
ee->wa_batchbuffer =
|
||||
i915_error_object_create(dev_priv,
|
||||
i915_error_object_create(i915,
|
||||
engine->scratch);
|
||||
request_record_user_bo(request, ee);
|
||||
|
||||
ee->ctx =
|
||||
i915_error_object_create(dev_priv,
|
||||
i915_error_object_create(i915,
|
||||
request->ctx->engine[i].state);
|
||||
|
||||
error->simulated |=
|
||||
|
@ -1505,27 +1484,24 @@ static void i915_gem_record_rings(struct drm_i915_private *dev_priv,
|
|||
ee->cpu_ring_head = ring->head;
|
||||
ee->cpu_ring_tail = ring->tail;
|
||||
ee->ringbuffer =
|
||||
i915_error_object_create(dev_priv, ring->vma);
|
||||
i915_error_object_create(i915, ring->vma);
|
||||
|
||||
engine_record_requests(engine, request, ee);
|
||||
}
|
||||
|
||||
ee->hws_page =
|
||||
i915_error_object_create(dev_priv,
|
||||
i915_error_object_create(i915,
|
||||
engine->status_page.vma);
|
||||
|
||||
ee->wa_ctx =
|
||||
i915_error_object_create(dev_priv, engine->wa_ctx.vma);
|
||||
ee->wa_ctx = i915_error_object_create(i915, engine->wa_ctx.vma);
|
||||
|
||||
ee->default_state =
|
||||
capture_object(dev_priv, engine->default_state);
|
||||
ee->default_state = capture_object(i915, engine->default_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
|
||||
struct i915_gpu_state *error,
|
||||
struct i915_address_space *vm,
|
||||
int idx)
|
||||
static void gem_capture_vm(struct i915_gpu_state *error,
|
||||
struct i915_address_space *vm,
|
||||
int idx)
|
||||
{
|
||||
struct drm_i915_error_buffer *active_bo;
|
||||
struct i915_vma *vma;
|
||||
|
@ -1548,8 +1524,7 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
|
|||
error->active_bo_count[idx] = count;
|
||||
}
|
||||
|
||||
static void i915_capture_active_buffers(struct drm_i915_private *dev_priv,
|
||||
struct i915_gpu_state *error)
|
||||
static void capture_active_buffers(struct i915_gpu_state *error)
|
||||
{
|
||||
int cnt = 0, i, j;
|
||||
|
||||
|
@ -1569,14 +1544,13 @@ static void i915_capture_active_buffers(struct drm_i915_private *dev_priv,
|
|||
for (j = 0; j < i && !found; j++)
|
||||
found = error->engine[j].vm == ee->vm;
|
||||
if (!found)
|
||||
i915_gem_capture_vm(dev_priv, error, ee->vm, cnt++);
|
||||
gem_capture_vm(error, ee->vm, cnt++);
|
||||
}
|
||||
}
|
||||
|
||||
static void i915_capture_pinned_buffers(struct drm_i915_private *dev_priv,
|
||||
struct i915_gpu_state *error)
|
||||
static void capture_pinned_buffers(struct i915_gpu_state *error)
|
||||
{
|
||||
struct i915_address_space *vm = &dev_priv->ggtt.base;
|
||||
struct i915_address_space *vm = &error->i915->ggtt.base;
|
||||
struct drm_i915_error_buffer *bo;
|
||||
struct i915_vma *vma;
|
||||
int count_inactive, count_active;
|
||||
|
@ -1626,9 +1600,9 @@ static void capture_uc_state(struct i915_gpu_state *error)
|
|||
}
|
||||
|
||||
/* Capture all registers which don't fit into another category. */
|
||||
static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
|
||||
struct i915_gpu_state *error)
|
||||
static void capture_reg_state(struct i915_gpu_state *error)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = error->i915;
|
||||
int i;
|
||||
|
||||
/* General organization
|
||||
|
@ -1725,24 +1699,25 @@ static void i915_error_capture_msg(struct drm_i915_private *dev_priv,
|
|||
engine_mask ? "reset" : "continue");
|
||||
}
|
||||
|
||||
static void i915_capture_gen_state(struct drm_i915_private *dev_priv,
|
||||
struct i915_gpu_state *error)
|
||||
static void capture_gen_state(struct i915_gpu_state *error)
|
||||
{
|
||||
error->awake = dev_priv->gt.awake;
|
||||
error->wakelock = atomic_read(&dev_priv->runtime_pm.wakeref_count);
|
||||
error->suspended = dev_priv->runtime_pm.suspended;
|
||||
struct drm_i915_private *i915 = error->i915;
|
||||
|
||||
error->awake = i915->gt.awake;
|
||||
error->wakelock = atomic_read(&i915->runtime_pm.wakeref_count);
|
||||
error->suspended = i915->runtime_pm.suspended;
|
||||
|
||||
error->iommu = -1;
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
error->iommu = intel_iommu_gfx_mapped;
|
||||
#endif
|
||||
error->reset_count = i915_reset_count(&dev_priv->gpu_error);
|
||||
error->suspend_count = dev_priv->suspend_count;
|
||||
error->reset_count = i915_reset_count(&i915->gpu_error);
|
||||
error->suspend_count = i915->suspend_count;
|
||||
|
||||
memcpy(&error->device_info,
|
||||
INTEL_INFO(dev_priv),
|
||||
INTEL_INFO(i915),
|
||||
sizeof(error->device_info));
|
||||
error->driver_caps = dev_priv->caps;
|
||||
error->driver_caps = i915->caps;
|
||||
}
|
||||
|
||||
static __always_inline void dup_param(const char *type, void *x)
|
||||
|
@ -1769,14 +1744,13 @@ static int capture(void *data)
|
|||
error->i915->gt.last_init_time);
|
||||
|
||||
capture_params(error);
|
||||
capture_gen_state(error);
|
||||
capture_uc_state(error);
|
||||
|
||||
i915_capture_gen_state(error->i915, error);
|
||||
i915_capture_reg_state(error->i915, error);
|
||||
i915_gem_record_fences(error->i915, error);
|
||||
i915_gem_record_rings(error->i915, error);
|
||||
i915_capture_active_buffers(error->i915, error);
|
||||
i915_capture_pinned_buffers(error->i915, error);
|
||||
capture_reg_state(error);
|
||||
gem_record_fences(error);
|
||||
gem_record_rings(error);
|
||||
capture_active_buffers(error);
|
||||
capture_pinned_buffers(error);
|
||||
|
||||
error->overlay = intel_overlay_capture_error_state(error->i915);
|
||||
error->display = intel_display_capture_error_state(error->i915);
|
||||
|
|
|
@ -415,6 +415,9 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
|
|||
if (READ_ONCE(rps->interrupts_enabled))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(IS_GEN11(dev_priv)))
|
||||
return;
|
||||
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
WARN_ON_ONCE(rps->pm_iir);
|
||||
WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
|
||||
|
@ -431,6 +434,9 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
|
|||
if (!READ_ONCE(rps->interrupts_enabled))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(IS_GEN11(dev_priv)))
|
||||
return;
|
||||
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
rps->interrupts_enabled = false;
|
||||
|
||||
|
@ -1071,7 +1077,7 @@ static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
|
|||
|
||||
static void notify_ring(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *rq = NULL;
|
||||
struct i915_request *rq = NULL;
|
||||
struct intel_wait *wait;
|
||||
|
||||
if (!engine->breadcrumbs.irq_armed)
|
||||
|
@ -1098,13 +1104,13 @@ static void notify_ring(struct intel_engine_cs *engine)
|
|||
*/
|
||||
if (i915_seqno_passed(intel_engine_get_seqno(engine),
|
||||
wait->seqno)) {
|
||||
struct drm_i915_gem_request *waiter = wait->request;
|
||||
struct i915_request *waiter = wait->request;
|
||||
|
||||
wakeup = true;
|
||||
if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
|
||||
&waiter->fence.flags) &&
|
||||
intel_wait_check_request(wait, waiter))
|
||||
rq = i915_gem_request_get(waiter);
|
||||
rq = i915_request_get(waiter);
|
||||
}
|
||||
|
||||
if (wakeup)
|
||||
|
@ -1117,7 +1123,8 @@ static void notify_ring(struct intel_engine_cs *engine)
|
|||
|
||||
if (rq) {
|
||||
dma_fence_signal(&rq->fence);
|
||||
i915_gem_request_put(rq);
|
||||
GEM_BUG_ON(!i915_request_completed(rq));
|
||||
i915_request_put(rq);
|
||||
}
|
||||
|
||||
trace_intel_engine_notify(engine, wait);
|
||||
|
@ -2755,6 +2762,156 @@ static void __fini_wedge(struct wedge_me *w)
|
|||
(W)->i915; \
|
||||
__fini_wedge((W)))
|
||||
|
||||
static __always_inline void
|
||||
gen11_cs_irq_handler(struct intel_engine_cs * const engine, const u32 iir)
|
||||
{
|
||||
gen8_cs_irq_handler(engine, iir, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gen11_gt_engine_irq_handler(struct drm_i915_private * const i915,
|
||||
const unsigned int bank,
|
||||
const unsigned int engine_n,
|
||||
const u16 iir)
|
||||
{
|
||||
struct intel_engine_cs ** const engine = i915->engine;
|
||||
|
||||
switch (bank) {
|
||||
case 0:
|
||||
switch (engine_n) {
|
||||
|
||||
case GEN11_RCS0:
|
||||
return gen11_cs_irq_handler(engine[RCS], iir);
|
||||
|
||||
case GEN11_BCS:
|
||||
return gen11_cs_irq_handler(engine[BCS], iir);
|
||||
}
|
||||
case 1:
|
||||
switch (engine_n) {
|
||||
|
||||
case GEN11_VCS(0):
|
||||
return gen11_cs_irq_handler(engine[_VCS(0)], iir);
|
||||
case GEN11_VCS(1):
|
||||
return gen11_cs_irq_handler(engine[_VCS(1)], iir);
|
||||
case GEN11_VCS(2):
|
||||
return gen11_cs_irq_handler(engine[_VCS(2)], iir);
|
||||
case GEN11_VCS(3):
|
||||
return gen11_cs_irq_handler(engine[_VCS(3)], iir);
|
||||
|
||||
case GEN11_VECS(0):
|
||||
return gen11_cs_irq_handler(engine[_VECS(0)], iir);
|
||||
case GEN11_VECS(1):
|
||||
return gen11_cs_irq_handler(engine[_VECS(1)], iir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u32
|
||||
gen11_gt_engine_intr(struct drm_i915_private * const i915,
|
||||
const unsigned int bank, const unsigned int bit)
|
||||
{
|
||||
void __iomem * const regs = i915->regs;
|
||||
u32 timeout_ts;
|
||||
u32 ident;
|
||||
|
||||
raw_reg_write(regs, GEN11_IIR_REG_SELECTOR(bank), BIT(bit));
|
||||
|
||||
/*
|
||||
* NB: Specs do not specify how long to spin wait,
|
||||
* so we do ~100us as an educated guess.
|
||||
*/
|
||||
timeout_ts = (local_clock() >> 10) + 100;
|
||||
do {
|
||||
ident = raw_reg_read(regs, GEN11_INTR_IDENTITY_REG(bank));
|
||||
} while (!(ident & GEN11_INTR_DATA_VALID) &&
|
||||
!time_after32(local_clock() >> 10, timeout_ts));
|
||||
|
||||
if (unlikely(!(ident & GEN11_INTR_DATA_VALID))) {
|
||||
DRM_ERROR("INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n",
|
||||
bank, bit, ident);
|
||||
return 0;
|
||||
}
|
||||
|
||||
raw_reg_write(regs, GEN11_INTR_IDENTITY_REG(bank),
|
||||
GEN11_INTR_DATA_VALID);
|
||||
|
||||
return ident & GEN11_INTR_ENGINE_MASK;
|
||||
}
|
||||
|
||||
static void
|
||||
gen11_gt_irq_handler(struct drm_i915_private * const i915,
|
||||
const u32 master_ctl)
|
||||
{
|
||||
void __iomem * const regs = i915->regs;
|
||||
unsigned int bank;
|
||||
|
||||
for (bank = 0; bank < 2; bank++) {
|
||||
unsigned long intr_dw;
|
||||
unsigned int bit;
|
||||
|
||||
if (!(master_ctl & GEN11_GT_DW_IRQ(bank)))
|
||||
continue;
|
||||
|
||||
intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank));
|
||||
|
||||
if (unlikely(!intr_dw)) {
|
||||
DRM_ERROR("GT_INTR_DW%u blank!\n", bank);
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_set_bit(bit, &intr_dw, 32) {
|
||||
const u16 iir = gen11_gt_engine_intr(i915, bank, bit);
|
||||
|
||||
if (unlikely(!iir))
|
||||
continue;
|
||||
|
||||
gen11_gt_engine_irq_handler(i915, bank, bit, iir);
|
||||
}
|
||||
|
||||
/* Clear must be after shared has been served for engine */
|
||||
raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t gen11_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct drm_i915_private * const i915 = to_i915(arg);
|
||||
void __iomem * const regs = i915->regs;
|
||||
u32 master_ctl;
|
||||
|
||||
if (!intel_irqs_enabled(i915))
|
||||
return IRQ_NONE;
|
||||
|
||||
master_ctl = raw_reg_read(regs, GEN11_GFX_MSTR_IRQ);
|
||||
master_ctl &= ~GEN11_MASTER_IRQ;
|
||||
if (!master_ctl)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Disable interrupts. */
|
||||
raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0);
|
||||
|
||||
/* Find, clear, then process each source of interrupt. */
|
||||
gen11_gt_irq_handler(i915, master_ctl);
|
||||
|
||||
/* IRQs are synced during runtime_suspend, we don't require a wakeref */
|
||||
if (master_ctl & GEN11_DISPLAY_IRQ) {
|
||||
const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL);
|
||||
|
||||
disable_rpm_wakeref_asserts(i915);
|
||||
/*
|
||||
* GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ
|
||||
* for the display related bits.
|
||||
*/
|
||||
gen8_de_irq_handler(i915, disp_ctl);
|
||||
enable_rpm_wakeref_asserts(i915);
|
||||
}
|
||||
|
||||
/* Acknowledge and enable interrupts. */
|
||||
raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ | master_ctl);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_reset_device - do process context error handling work
|
||||
* @dev_priv: i915 device private
|
||||
|
@ -3180,6 +3337,42 @@ static void gen8_irq_reset(struct drm_device *dev)
|
|||
ibx_irq_reset(dev_priv);
|
||||
}
|
||||
|
||||
static void gen11_gt_irq_reset(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
/* Disable RCS, BCS, VCS and VECS class engines. */
|
||||
I915_WRITE(GEN11_RENDER_COPY_INTR_ENABLE, 0);
|
||||
I915_WRITE(GEN11_VCS_VECS_INTR_ENABLE, 0);
|
||||
|
||||
/* Restore masks irqs on RCS, BCS, VCS and VECS engines. */
|
||||
I915_WRITE(GEN11_RCS0_RSVD_INTR_MASK, ~0);
|
||||
I915_WRITE(GEN11_BCS_RSVD_INTR_MASK, ~0);
|
||||
I915_WRITE(GEN11_VCS0_VCS1_INTR_MASK, ~0);
|
||||
I915_WRITE(GEN11_VCS2_VCS3_INTR_MASK, ~0);
|
||||
I915_WRITE(GEN11_VECS0_VECS1_INTR_MASK, ~0);
|
||||
}
|
||||
|
||||
static void gen11_irq_reset(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int pipe;
|
||||
|
||||
I915_WRITE(GEN11_GFX_MSTR_IRQ, 0);
|
||||
POSTING_READ(GEN11_GFX_MSTR_IRQ);
|
||||
|
||||
gen11_gt_irq_reset(dev_priv);
|
||||
|
||||
I915_WRITE(GEN11_DISPLAY_INT_CTL, 0);
|
||||
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
if (intel_display_power_is_enabled(dev_priv,
|
||||
POWER_DOMAIN_PIPE(pipe)))
|
||||
GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
|
||||
|
||||
GEN3_IRQ_RESET(GEN8_DE_PORT_);
|
||||
GEN3_IRQ_RESET(GEN8_DE_MISC_);
|
||||
GEN3_IRQ_RESET(GEN8_PCU_);
|
||||
}
|
||||
|
||||
void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
|
||||
u8 pipe_mask)
|
||||
{
|
||||
|
@ -3677,6 +3870,41 @@ static int gen8_irq_postinstall(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
const u32 irqs = GT_RENDER_USER_INTERRUPT | GT_CONTEXT_SWITCH_INTERRUPT;
|
||||
|
||||
BUILD_BUG_ON(irqs & 0xffff0000);
|
||||
|
||||
/* Enable RCS, BCS, VCS and VECS class interrupts. */
|
||||
I915_WRITE(GEN11_RENDER_COPY_INTR_ENABLE, irqs << 16 | irqs);
|
||||
I915_WRITE(GEN11_VCS_VECS_INTR_ENABLE, irqs << 16 | irqs);
|
||||
|
||||
/* Unmask irqs on RCS, BCS, VCS and VECS engines. */
|
||||
I915_WRITE(GEN11_RCS0_RSVD_INTR_MASK, ~(irqs << 16));
|
||||
I915_WRITE(GEN11_BCS_RSVD_INTR_MASK, ~(irqs << 16));
|
||||
I915_WRITE(GEN11_VCS0_VCS1_INTR_MASK, ~(irqs | irqs << 16));
|
||||
I915_WRITE(GEN11_VCS2_VCS3_INTR_MASK, ~(irqs | irqs << 16));
|
||||
I915_WRITE(GEN11_VECS0_VECS1_INTR_MASK, ~(irqs | irqs << 16));
|
||||
|
||||
dev_priv->pm_imr = 0xffffffff; /* TODO */
|
||||
}
|
||||
|
||||
static int gen11_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
gen11_gt_irq_postinstall(dev_priv);
|
||||
gen8_de_irq_postinstall(dev_priv);
|
||||
|
||||
I915_WRITE(GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE);
|
||||
|
||||
I915_WRITE(GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ);
|
||||
POSTING_READ(GEN11_GFX_MSTR_IRQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cherryview_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
@ -4125,6 +4353,14 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
|
|||
dev->driver->enable_vblank = i965_enable_vblank;
|
||||
dev->driver->disable_vblank = i965_disable_vblank;
|
||||
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
|
||||
} else if (INTEL_GEN(dev_priv) >= 11) {
|
||||
dev->driver->irq_handler = gen11_irq_handler;
|
||||
dev->driver->irq_preinstall = gen11_irq_reset;
|
||||
dev->driver->irq_postinstall = gen11_irq_postinstall;
|
||||
dev->driver->irq_uninstall = gen11_irq_reset;
|
||||
dev->driver->enable_vblank = gen8_enable_vblank;
|
||||
dev->driver->disable_vblank = gen8_disable_vblank;
|
||||
dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup;
|
||||
} else if (INTEL_GEN(dev_priv) >= 8) {
|
||||
dev->driver->irq_handler = gen8_irq_handler;
|
||||
dev->driver->irq_preinstall = gen8_irq_reset;
|
||||
|
|
|
@ -594,7 +594,8 @@ static const struct intel_device_info intel_cannonlake_info = {
|
|||
GEN10_FEATURES, \
|
||||
GEN(11), \
|
||||
.ddb_size = 2048, \
|
||||
.has_csr = 0
|
||||
.has_csr = 0, \
|
||||
.has_logical_ring_elsq = 1
|
||||
|
||||
static const struct intel_device_info intel_icelake_11_info = {
|
||||
GEN11_FEATURES,
|
||||
|
@ -664,6 +665,7 @@ static const struct pci_device_id pciidlist[] = {
|
|||
INTEL_CFL_U_GT2_IDS(&intel_coffeelake_gt2_info),
|
||||
INTEL_CFL_U_GT3_IDS(&intel_coffeelake_gt3_info),
|
||||
INTEL_CNL_IDS(&intel_cannonlake_info),
|
||||
INTEL_ICL_11_IDS(&intel_icelake_11_info),
|
||||
{0, 0, 0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||
|
|
|
@ -1303,9 +1303,8 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream)
|
|||
*/
|
||||
mutex_lock(&dev_priv->drm.struct_mutex);
|
||||
dev_priv->perf.oa.exclusive_stream = NULL;
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
|
||||
dev_priv->perf.oa.ops.disable_metric_set(dev_priv);
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
|
||||
free_oa_buffer(dev_priv);
|
||||
|
||||
|
@ -1630,10 +1629,10 @@ static void gen8_update_reg_state_unlocked(struct i915_gem_context *ctx,
|
|||
* Same as gen8_update_reg_state_unlocked only through the batchbuffer. This
|
||||
* is only used by the kernel context.
|
||||
*/
|
||||
static int gen8_emit_oa_config(struct drm_i915_gem_request *req,
|
||||
static int gen8_emit_oa_config(struct i915_request *rq,
|
||||
const struct i915_oa_config *oa_config)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = req->i915;
|
||||
struct drm_i915_private *dev_priv = rq->i915;
|
||||
/* The MMIO offsets for Flex EU registers aren't contiguous */
|
||||
u32 flex_mmio[] = {
|
||||
i915_mmio_reg_offset(EU_PERF_CNTL0),
|
||||
|
@ -1647,7 +1646,7 @@ static int gen8_emit_oa_config(struct drm_i915_gem_request *req,
|
|||
u32 *cs;
|
||||
int i;
|
||||
|
||||
cs = intel_ring_begin(req, ARRAY_SIZE(flex_mmio) * 2 + 4);
|
||||
cs = intel_ring_begin(rq, ARRAY_SIZE(flex_mmio) * 2 + 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1685,7 +1684,7 @@ static int gen8_emit_oa_config(struct drm_i915_gem_request *req,
|
|||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1695,38 +1694,38 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
|
|||
{
|
||||
struct intel_engine_cs *engine = dev_priv->engine[RCS];
|
||||
struct i915_gem_timeline *timeline;
|
||||
struct drm_i915_gem_request *req;
|
||||
struct i915_request *rq;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
i915_retire_requests(dev_priv);
|
||||
|
||||
req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
rq = i915_request_alloc(engine, dev_priv->kernel_context);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
ret = gen8_emit_oa_config(req, oa_config);
|
||||
ret = gen8_emit_oa_config(rq, oa_config);
|
||||
if (ret) {
|
||||
i915_add_request(req);
|
||||
i915_request_add(rq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Queue this switch after all other activity */
|
||||
list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
|
||||
struct drm_i915_gem_request *prev;
|
||||
struct i915_request *prev;
|
||||
struct intel_timeline *tl;
|
||||
|
||||
tl = &timeline->engine[engine->id];
|
||||
prev = i915_gem_active_raw(&tl->last_request,
|
||||
&dev_priv->drm.struct_mutex);
|
||||
if (prev)
|
||||
i915_sw_fence_await_sw_fence_gfp(&req->submit,
|
||||
i915_sw_fence_await_sw_fence_gfp(&rq->submit,
|
||||
&prev->submit,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
i915_add_request(req);
|
||||
i915_request_add(rq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1756,22 +1755,13 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
|
|||
* Note: it's only the RCS/Render context that has any OA state.
|
||||
*/
|
||||
static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
|
||||
const struct i915_oa_config *oa_config,
|
||||
bool interruptible)
|
||||
const struct i915_oa_config *oa_config)
|
||||
{
|
||||
struct i915_gem_context *ctx;
|
||||
int ret;
|
||||
unsigned int wait_flags = I915_WAIT_LOCKED;
|
||||
|
||||
if (interruptible) {
|
||||
ret = i915_mutex_lock_interruptible(&dev_priv->drm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
wait_flags |= I915_WAIT_INTERRUPTIBLE;
|
||||
} else {
|
||||
mutex_lock(&dev_priv->drm.struct_mutex);
|
||||
}
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
|
||||
/* Switch away from any user context. */
|
||||
ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config);
|
||||
|
@ -1819,8 +1809,6 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1863,7 +1851,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv,
|
|||
* to make sure all slices/subslices are ON before writing to NOA
|
||||
* registers.
|
||||
*/
|
||||
ret = gen8_configure_all_contexts(dev_priv, oa_config, true);
|
||||
ret = gen8_configure_all_contexts(dev_priv, oa_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1878,7 +1866,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv,
|
|||
static void gen8_disable_metric_set(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
/* Reset all contexts' slices/subslices configurations. */
|
||||
gen8_configure_all_contexts(dev_priv, NULL, false);
|
||||
gen8_configure_all_contexts(dev_priv, NULL);
|
||||
|
||||
I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) &
|
||||
~GT_NOA_ENABLE));
|
||||
|
@ -1888,7 +1876,7 @@ static void gen8_disable_metric_set(struct drm_i915_private *dev_priv)
|
|||
static void gen10_disable_metric_set(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
/* Reset all contexts' slices/subslices configurations. */
|
||||
gen8_configure_all_contexts(dev_priv, NULL, false);
|
||||
gen8_configure_all_contexts(dev_priv, NULL);
|
||||
|
||||
/* Make sure we disable noa to save power. */
|
||||
I915_WRITE(RPM_CONFIG1,
|
||||
|
@ -2138,6 +2126,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
|
|||
if (ret)
|
||||
goto err_oa_buf_alloc;
|
||||
|
||||
ret = i915_mutex_lock_interruptible(&dev_priv->drm);
|
||||
if (ret)
|
||||
goto err_lock;
|
||||
|
||||
ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv,
|
||||
stream->oa_config);
|
||||
if (ret)
|
||||
|
@ -2145,23 +2137,17 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
|
|||
|
||||
stream->ops = &i915_oa_stream_ops;
|
||||
|
||||
/* Lock device for exclusive_stream access late because
|
||||
* enable_metric_set() might lock as well on gen8+.
|
||||
*/
|
||||
ret = i915_mutex_lock_interruptible(&dev_priv->drm);
|
||||
if (ret)
|
||||
goto err_lock;
|
||||
|
||||
dev_priv->perf.oa.exclusive_stream = stream;
|
||||
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_lock:
|
||||
dev_priv->perf.oa.ops.disable_metric_set(dev_priv);
|
||||
|
||||
err_enable:
|
||||
dev_priv->perf.oa.ops.disable_metric_set(dev_priv);
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
|
||||
err_lock:
|
||||
free_oa_buffer(dev_priv);
|
||||
|
||||
err_oa_buf_alloc:
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright © 2018 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_query.h"
|
||||
#include <uapi/drm/i915_drm.h>
|
||||
|
||||
static int query_topology_info(struct drm_i915_private *dev_priv,
|
||||
struct drm_i915_query_item *query_item)
|
||||
{
|
||||
const struct sseu_dev_info *sseu = &INTEL_INFO(dev_priv)->sseu;
|
||||
struct drm_i915_query_topology_info topo;
|
||||
u32 slice_length, subslice_length, eu_length, total_length;
|
||||
|
||||
if (query_item->flags != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (sseu->max_slices == 0)
|
||||
return -ENODEV;
|
||||
|
||||
BUILD_BUG_ON(sizeof(u8) != sizeof(sseu->slice_mask));
|
||||
|
||||
slice_length = sizeof(sseu->slice_mask);
|
||||
subslice_length = sseu->max_slices *
|
||||
DIV_ROUND_UP(sseu->max_subslices,
|
||||
sizeof(sseu->subslice_mask[0]) * BITS_PER_BYTE);
|
||||
eu_length = sseu->max_slices * sseu->max_subslices *
|
||||
DIV_ROUND_UP(sseu->max_eus_per_subslice, BITS_PER_BYTE);
|
||||
|
||||
total_length = sizeof(topo) + slice_length + subslice_length + eu_length;
|
||||
|
||||
if (query_item->length == 0)
|
||||
return total_length;
|
||||
|
||||
if (query_item->length < total_length)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&topo, u64_to_user_ptr(query_item->data_ptr),
|
||||
sizeof(topo)))
|
||||
return -EFAULT;
|
||||
|
||||
if (topo.flags != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, u64_to_user_ptr(query_item->data_ptr),
|
||||
total_length))
|
||||
return -EFAULT;
|
||||
|
||||
memset(&topo, 0, sizeof(topo));
|
||||
topo.max_slices = sseu->max_slices;
|
||||
topo.max_subslices = sseu->max_subslices;
|
||||
topo.max_eus_per_subslice = sseu->max_eus_per_subslice;
|
||||
|
||||
topo.subslice_offset = slice_length;
|
||||
topo.subslice_stride = DIV_ROUND_UP(sseu->max_subslices, BITS_PER_BYTE);
|
||||
topo.eu_offset = slice_length + subslice_length;
|
||||
topo.eu_stride =
|
||||
DIV_ROUND_UP(sseu->max_eus_per_subslice, BITS_PER_BYTE);
|
||||
|
||||
if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr),
|
||||
&topo, sizeof(topo)))
|
||||
return -EFAULT;
|
||||
|
||||
if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + sizeof(topo)),
|
||||
&sseu->slice_mask, slice_length))
|
||||
return -EFAULT;
|
||||
|
||||
if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr +
|
||||
sizeof(topo) + slice_length),
|
||||
sseu->subslice_mask, subslice_length))
|
||||
return -EFAULT;
|
||||
|
||||
if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr +
|
||||
sizeof(topo) +
|
||||
slice_length + subslice_length),
|
||||
sseu->eu_mask, eu_length))
|
||||
return -EFAULT;
|
||||
|
||||
return total_length;
|
||||
}
|
||||
|
||||
static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv,
|
||||
struct drm_i915_query_item *query_item) = {
|
||||
query_topology_info,
|
||||
};
|
||||
|
||||
int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_query *args = data;
|
||||
struct drm_i915_query_item __user *user_item_ptr =
|
||||
u64_to_user_ptr(args->items_ptr);
|
||||
u32 i;
|
||||
|
||||
if (args->flags != 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < args->num_items; i++, user_item_ptr++) {
|
||||
struct drm_i915_query_item item;
|
||||
u64 func_idx;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&item, user_item_ptr, sizeof(item)))
|
||||
return -EFAULT;
|
||||
|
||||
if (item.query_id == 0)
|
||||
return -EINVAL;
|
||||
|
||||
func_idx = item.query_id - 1;
|
||||
|
||||
if (func_idx < ARRAY_SIZE(i915_query_funcs))
|
||||
ret = i915_query_funcs[func_idx](dev_priv, &item);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
/* Only write the length back to userspace if they differ. */
|
||||
if (ret != item.length && put_user(ret, &user_item_ptr->length))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright © 2018 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef _I915_QUERY_H_
|
||||
#define _I915_QUERY_H_
|
||||
|
||||
struct drm_device;
|
||||
struct drm_file;
|
||||
|
||||
int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
|
||||
|
||||
#endif
|
|
@ -178,6 +178,9 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
|||
#define BCS_HW 2
|
||||
#define VECS_HW 3
|
||||
#define VCS2_HW 4
|
||||
#define VCS3_HW 6
|
||||
#define VCS4_HW 7
|
||||
#define VECS2_HW 12
|
||||
|
||||
/* Engine class */
|
||||
|
||||
|
@ -188,7 +191,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
|||
#define OTHER_CLASS 4
|
||||
#define MAX_ENGINE_CLASS 4
|
||||
|
||||
#define MAX_ENGINE_INSTANCE 1
|
||||
#define MAX_ENGINE_INSTANCE 3
|
||||
|
||||
/* PCI config space */
|
||||
|
||||
|
@ -2342,7 +2345,13 @@ enum i915_power_well_id {
|
|||
#define BSD_RING_BASE 0x04000
|
||||
#define GEN6_BSD_RING_BASE 0x12000
|
||||
#define GEN8_BSD2_RING_BASE 0x1c000
|
||||
#define GEN11_BSD_RING_BASE 0x1c0000
|
||||
#define GEN11_BSD2_RING_BASE 0x1c4000
|
||||
#define GEN11_BSD3_RING_BASE 0x1d0000
|
||||
#define GEN11_BSD4_RING_BASE 0x1d4000
|
||||
#define VEBOX_RING_BASE 0x1a000
|
||||
#define GEN11_VEBOX_RING_BASE 0x1c8000
|
||||
#define GEN11_VEBOX2_RING_BASE 0x1d8000
|
||||
#define BLT_RING_BASE 0x22000
|
||||
#define RING_TAIL(base) _MMIO((base)+0x30)
|
||||
#define RING_HEAD(base) _MMIO((base)+0x34)
|
||||
|
@ -2807,6 +2816,13 @@ enum i915_power_well_id {
|
|||
#define GEN9_RCS_FE_FSM2 _MMIO(0x22a4)
|
||||
|
||||
/* Fuse readout registers for GT */
|
||||
#define HSW_PAVP_FUSE1 _MMIO(0x911C)
|
||||
#define HSW_F1_EU_DIS_SHIFT 16
|
||||
#define HSW_F1_EU_DIS_MASK (0x3 << HSW_F1_EU_DIS_SHIFT)
|
||||
#define HSW_F1_EU_DIS_10EUS 0
|
||||
#define HSW_F1_EU_DIS_8EUS 1
|
||||
#define HSW_F1_EU_DIS_6EUS 2
|
||||
|
||||
#define CHV_FUSE_GT _MMIO(VLV_DISPLAY_BASE + 0x2168)
|
||||
#define CHV_FGT_DISABLE_SS0 (1 << 10)
|
||||
#define CHV_FGT_DISABLE_SS1 (1 << 11)
|
||||
|
@ -3896,6 +3912,12 @@ enum {
|
|||
|
||||
#define GEN8_CTX_ID_SHIFT 32
|
||||
#define GEN8_CTX_ID_WIDTH 21
|
||||
#define GEN11_SW_CTX_ID_SHIFT 37
|
||||
#define GEN11_SW_CTX_ID_WIDTH 11
|
||||
#define GEN11_ENGINE_CLASS_SHIFT 61
|
||||
#define GEN11_ENGINE_CLASS_WIDTH 3
|
||||
#define GEN11_ENGINE_INSTANCE_SHIFT 48
|
||||
#define GEN11_ENGINE_INSTANCE_WIDTH 6
|
||||
|
||||
#define CHV_CLK_CTL1 _MMIO(0x101100)
|
||||
#define VLV_CLK_CTL2 _MMIO(0x101104)
|
||||
|
@ -3943,6 +3965,9 @@ enum {
|
|||
#define SARBUNIT_CLKGATE_DIS (1 << 5)
|
||||
#define RCCUNIT_CLKGATE_DIS (1 << 7)
|
||||
|
||||
#define SUBSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9524)
|
||||
#define GWUNIT_CLKGATE_DIS (1 << 16)
|
||||
|
||||
#define UNSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9434)
|
||||
#define VFUNIT_CLKGATE_DIS (1 << 20)
|
||||
|
||||
|
@ -5347,8 +5372,8 @@ enum {
|
|||
#define _DPF_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64520)
|
||||
#define _DPF_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64524)
|
||||
|
||||
#define DP_AUX_CH_CTL(port) _MMIO_PORT(port, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)
|
||||
#define DP_AUX_CH_DATA(port, i) _MMIO(_PORT(port, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
|
||||
#define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)
|
||||
#define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
|
||||
|
||||
#define DP_AUX_CH_CTL_SEND_BUSY (1 << 31)
|
||||
#define DP_AUX_CH_CTL_DONE (1 << 30)
|
||||
|
@ -7897,8 +7922,8 @@ enum {
|
|||
#define _PCH_DPD_AUX_CH_DATA4 0xe4320
|
||||
#define _PCH_DPD_AUX_CH_DATA5 0xe4324
|
||||
|
||||
#define PCH_DP_AUX_CH_CTL(port) _MMIO_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_CTL, _PCH_DPC_AUX_CH_CTL)
|
||||
#define PCH_DP_AUX_CH_DATA(port, i) _MMIO(_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_DATA1, _PCH_DPC_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
|
||||
#define PCH_DP_AUX_CH_CTL(aux_ch) _MMIO_PORT((aux_ch) - AUX_CH_B, _PCH_DPB_AUX_CH_CTL, _PCH_DPC_AUX_CH_CTL)
|
||||
#define PCH_DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT((aux_ch) - AUX_CH_B, _PCH_DPB_AUX_CH_DATA1, _PCH_DPC_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
|
||||
|
||||
/* CPT */
|
||||
#define PORT_TRANS_A_SEL_CPT 0
|
||||
|
@ -7998,9 +8023,13 @@ enum {
|
|||
#define VLV_GTLC_PW_RENDER_STATUS_MASK (1 << 7)
|
||||
#define FORCEWAKE_MT _MMIO(0xa188) /* multi-threaded */
|
||||
#define FORCEWAKE_MEDIA_GEN9 _MMIO(0xa270)
|
||||
#define FORCEWAKE_MEDIA_VDBOX_GEN11(n) _MMIO(0xa540 + (n) * 4)
|
||||
#define FORCEWAKE_MEDIA_VEBOX_GEN11(n) _MMIO(0xa560 + (n) * 4)
|
||||
#define FORCEWAKE_RENDER_GEN9 _MMIO(0xa278)
|
||||
#define FORCEWAKE_BLITTER_GEN9 _MMIO(0xa188)
|
||||
#define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0x0D88)
|
||||
#define FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(n) _MMIO(0x0D50 + (n) * 4)
|
||||
#define FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(n) _MMIO(0x0D70 + (n) * 4)
|
||||
#define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0x0D84)
|
||||
#define FORCEWAKE_ACK_BLITTER_GEN9 _MMIO(0x130044)
|
||||
#define FORCEWAKE_KERNEL BIT(0)
|
||||
|
|
|
@ -37,7 +37,8 @@ static const char *i915_fence_get_driver_name(struct dma_fence *fence)
|
|||
|
||||
static const char *i915_fence_get_timeline_name(struct dma_fence *fence)
|
||||
{
|
||||
/* The timeline struct (as part of the ppgtt underneath a context)
|
||||
/*
|
||||
* The timeline struct (as part of the ppgtt underneath a context)
|
||||
* may be freed when the request is no longer in use by the GPU.
|
||||
* We could extend the life of a context to beyond that of all
|
||||
* fences, possibly keeping the hw resource around indefinitely,
|
||||
|
@ -53,7 +54,7 @@ static const char *i915_fence_get_timeline_name(struct dma_fence *fence)
|
|||
|
||||
static bool i915_fence_signaled(struct dma_fence *fence)
|
||||
{
|
||||
return i915_gem_request_completed(to_request(fence));
|
||||
return i915_request_completed(to_request(fence));
|
||||
}
|
||||
|
||||
static bool i915_fence_enable_signaling(struct dma_fence *fence)
|
||||
|
@ -69,22 +70,23 @@ static signed long i915_fence_wait(struct dma_fence *fence,
|
|||
bool interruptible,
|
||||
signed long timeout)
|
||||
{
|
||||
return i915_wait_request(to_request(fence), interruptible, timeout);
|
||||
return i915_request_wait(to_request(fence), interruptible, timeout);
|
||||
}
|
||||
|
||||
static void i915_fence_release(struct dma_fence *fence)
|
||||
{
|
||||
struct drm_i915_gem_request *req = to_request(fence);
|
||||
struct i915_request *rq = to_request(fence);
|
||||
|
||||
/* The request is put onto a RCU freelist (i.e. the address
|
||||
/*
|
||||
* The request is put onto a RCU freelist (i.e. the address
|
||||
* is immediately reused), mark the fences as being freed now.
|
||||
* Otherwise the debugobjects for the fences are only marked as
|
||||
* freed when the slab cache itself is freed, and so we would get
|
||||
* caught trying to reuse dead objects.
|
||||
*/
|
||||
i915_sw_fence_fini(&req->submit);
|
||||
i915_sw_fence_fini(&rq->submit);
|
||||
|
||||
kmem_cache_free(req->i915->requests, req);
|
||||
kmem_cache_free(rq->i915->requests, rq);
|
||||
}
|
||||
|
||||
const struct dma_fence_ops i915_fence_ops = {
|
||||
|
@ -97,7 +99,7 @@ const struct dma_fence_ops i915_fence_ops = {
|
|||
};
|
||||
|
||||
static inline void
|
||||
i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
|
||||
i915_request_remove_from_client(struct i915_request *request)
|
||||
{
|
||||
struct drm_i915_file_private *file_priv;
|
||||
|
||||
|
@ -215,9 +217,9 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
|
|||
struct intel_timeline *tl = engine->timeline;
|
||||
|
||||
if (!i915_seqno_passed(seqno, tl->seqno)) {
|
||||
/* spin until threads are complete */
|
||||
while (intel_breadcrumbs_busy(engine))
|
||||
cond_resched();
|
||||
/* Flush any waiters before we reuse the seqno */
|
||||
intel_engine_disarm_breadcrumbs(engine);
|
||||
GEM_BUG_ON(!list_empty(&engine->breadcrumbs.signals));
|
||||
}
|
||||
|
||||
/* Check we are idle before we fiddle with hw state! */
|
||||
|
@ -238,17 +240,15 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
|
|||
|
||||
int i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *i915 = to_i915(dev);
|
||||
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
lockdep_assert_held(&i915->drm.struct_mutex);
|
||||
|
||||
if (seqno == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* HWS page needs to be set less than what we
|
||||
* will inject to ring
|
||||
*/
|
||||
return reset_all_global_seqno(dev_priv, seqno - 1);
|
||||
/* HWS page needs to be set less than what we will inject to ring */
|
||||
return reset_all_global_seqno(i915, seqno - 1);
|
||||
}
|
||||
|
||||
static void mark_busy(struct drm_i915_private *i915)
|
||||
|
@ -331,16 +331,17 @@ static void unreserve_engine(struct intel_engine_cs *engine)
|
|||
}
|
||||
|
||||
void i915_gem_retire_noop(struct i915_gem_active *active,
|
||||
struct drm_i915_gem_request *request)
|
||||
struct i915_request *request)
|
||||
{
|
||||
/* Space left intentionally blank */
|
||||
}
|
||||
|
||||
static void advance_ring(struct drm_i915_gem_request *request)
|
||||
static void advance_ring(struct i915_request *request)
|
||||
{
|
||||
unsigned int tail;
|
||||
|
||||
/* We know the GPU must have read the request to have
|
||||
/*
|
||||
* We know the GPU must have read the request to have
|
||||
* sent us the seqno + interrupt, so use the position
|
||||
* of tail of the request to update the last known position
|
||||
* of the GPU head.
|
||||
|
@ -349,7 +350,8 @@ static void advance_ring(struct drm_i915_gem_request *request)
|
|||
* completion order.
|
||||
*/
|
||||
if (list_is_last(&request->ring_link, &request->ring->request_list)) {
|
||||
/* We may race here with execlists resubmitting this request
|
||||
/*
|
||||
* We may race here with execlists resubmitting this request
|
||||
* as we retire it. The resubmission will move the ring->tail
|
||||
* forwards (to request->wa_tail). We either read the
|
||||
* current value that was written to hw, or the value that
|
||||
|
@ -365,30 +367,30 @@ static void advance_ring(struct drm_i915_gem_request *request)
|
|||
request->ring->head = tail;
|
||||
}
|
||||
|
||||
static void free_capture_list(struct drm_i915_gem_request *request)
|
||||
static void free_capture_list(struct i915_request *request)
|
||||
{
|
||||
struct i915_gem_capture_list *capture;
|
||||
struct i915_capture_list *capture;
|
||||
|
||||
capture = request->capture_list;
|
||||
while (capture) {
|
||||
struct i915_gem_capture_list *next = capture->next;
|
||||
struct i915_capture_list *next = capture->next;
|
||||
|
||||
kfree(capture);
|
||||
capture = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void i915_gem_request_retire(struct drm_i915_gem_request *request)
|
||||
static void i915_request_retire(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct i915_gem_active *active, *next;
|
||||
|
||||
lockdep_assert_held(&request->i915->drm.struct_mutex);
|
||||
GEM_BUG_ON(!i915_sw_fence_signaled(&request->submit));
|
||||
GEM_BUG_ON(!i915_gem_request_completed(request));
|
||||
GEM_BUG_ON(!i915_request_completed(request));
|
||||
GEM_BUG_ON(!request->i915->gt.active_requests);
|
||||
|
||||
trace_i915_gem_request_retire(request);
|
||||
trace_i915_request_retire(request);
|
||||
|
||||
spin_lock_irq(&engine->timeline->lock);
|
||||
list_del_init(&request->link);
|
||||
|
@ -399,7 +401,8 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
|
|||
|
||||
free_capture_list(request);
|
||||
|
||||
/* Walk through the active list, calling retire on each. This allows
|
||||
/*
|
||||
* Walk through the active list, calling retire on each. This allows
|
||||
* objects to track their GPU activity and mark themselves as idle
|
||||
* when their *last* active request is completed (updating state
|
||||
* tracking lists for eviction, active references for GEM, etc).
|
||||
|
@ -409,7 +412,8 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
|
|||
* the node after the callback).
|
||||
*/
|
||||
list_for_each_entry_safe(active, next, &request->active_list, link) {
|
||||
/* In microbenchmarks or focusing upon time inside the kernel,
|
||||
/*
|
||||
* In microbenchmarks or focusing upon time inside the kernel,
|
||||
* we may spend an inordinate amount of time simply handling
|
||||
* the retirement of requests and processing their callbacks.
|
||||
* Of which, this loop itself is particularly hot due to the
|
||||
|
@ -426,15 +430,16 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
|
|||
active->retire(active, request);
|
||||
}
|
||||
|
||||
i915_gem_request_remove_from_client(request);
|
||||
i915_request_remove_from_client(request);
|
||||
|
||||
/* Retirement decays the ban score as it is a sign of ctx progress */
|
||||
atomic_dec_if_positive(&request->ctx->ban_score);
|
||||
|
||||
/* The backing object for the context is done after switching to the
|
||||
/*
|
||||
* The backing object for the context is done after switching to the
|
||||
* *next* context. Therefore we cannot retire the previous context until
|
||||
* the next context has already started running. However, since we
|
||||
* cannot take the required locks at i915_gem_request_submit() we
|
||||
* cannot take the required locks at i915_request_submit() we
|
||||
* defer the unpinning of the active context to now, retirement of
|
||||
* the subsequent request.
|
||||
*/
|
||||
|
@ -454,26 +459,26 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
|
|||
spin_unlock_irq(&request->lock);
|
||||
|
||||
i915_priotree_fini(request->i915, &request->priotree);
|
||||
i915_gem_request_put(request);
|
||||
i915_request_put(request);
|
||||
}
|
||||
|
||||
void i915_gem_request_retire_upto(struct drm_i915_gem_request *req)
|
||||
void i915_request_retire_upto(struct i915_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct drm_i915_gem_request *tmp;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
struct i915_request *tmp;
|
||||
|
||||
lockdep_assert_held(&req->i915->drm.struct_mutex);
|
||||
GEM_BUG_ON(!i915_gem_request_completed(req));
|
||||
lockdep_assert_held(&rq->i915->drm.struct_mutex);
|
||||
GEM_BUG_ON(!i915_request_completed(rq));
|
||||
|
||||
if (list_empty(&req->link))
|
||||
if (list_empty(&rq->link))
|
||||
return;
|
||||
|
||||
do {
|
||||
tmp = list_first_entry(&engine->timeline->requests,
|
||||
typeof(*tmp), link);
|
||||
|
||||
i915_gem_request_retire(tmp);
|
||||
} while (tmp != req);
|
||||
i915_request_retire(tmp);
|
||||
} while (tmp != rq);
|
||||
}
|
||||
|
||||
static u32 timeline_get_seqno(struct intel_timeline *tl)
|
||||
|
@ -481,7 +486,7 @@ static u32 timeline_get_seqno(struct intel_timeline *tl)
|
|||
return ++tl->seqno;
|
||||
}
|
||||
|
||||
void __i915_gem_request_submit(struct drm_i915_gem_request *request)
|
||||
void __i915_request_submit(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_timeline *timeline;
|
||||
|
@ -490,8 +495,6 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request)
|
|||
GEM_BUG_ON(!irqs_disabled());
|
||||
lockdep_assert_held(&engine->timeline->lock);
|
||||
|
||||
trace_i915_gem_request_execute(request);
|
||||
|
||||
/* Transfer from per-context onto the global per-engine timeline */
|
||||
timeline = engine->timeline;
|
||||
GEM_BUG_ON(timeline == request->timeline);
|
||||
|
@ -515,10 +518,12 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request)
|
|||
list_move_tail(&request->link, &timeline->requests);
|
||||
spin_unlock(&request->timeline->lock);
|
||||
|
||||
trace_i915_request_execute(request);
|
||||
|
||||
wake_up_all(&request->execute);
|
||||
}
|
||||
|
||||
void i915_gem_request_submit(struct drm_i915_gem_request *request)
|
||||
void i915_request_submit(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
unsigned long flags;
|
||||
|
@ -526,12 +531,12 @@ void i915_gem_request_submit(struct drm_i915_gem_request *request)
|
|||
/* Will be called from irq-context when using foreign fences. */
|
||||
spin_lock_irqsave(&engine->timeline->lock, flags);
|
||||
|
||||
__i915_gem_request_submit(request);
|
||||
__i915_request_submit(request);
|
||||
|
||||
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
||||
}
|
||||
|
||||
void __i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
|
||||
void __i915_request_unsubmit(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_timeline *timeline;
|
||||
|
@ -539,7 +544,8 @@ void __i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
|
|||
GEM_BUG_ON(!irqs_disabled());
|
||||
lockdep_assert_held(&engine->timeline->lock);
|
||||
|
||||
/* Only unwind in reverse order, required so that the per-context list
|
||||
/*
|
||||
* Only unwind in reverse order, required so that the per-context list
|
||||
* is kept in seqno/ring order.
|
||||
*/
|
||||
GEM_BUG_ON(!request->global_seqno);
|
||||
|
@ -563,15 +569,16 @@ void __i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
|
|||
list_move(&request->link, &timeline->requests);
|
||||
spin_unlock(&timeline->lock);
|
||||
|
||||
/* We don't need to wake_up any waiters on request->execute, they
|
||||
/*
|
||||
* We don't need to wake_up any waiters on request->execute, they
|
||||
* will get woken by any other event or us re-adding this request
|
||||
* to the engine timeline (__i915_gem_request_submit()). The waiters
|
||||
* to the engine timeline (__i915_request_submit()). The waiters
|
||||
* should be quite adapt at finding that the request now has a new
|
||||
* global_seqno to the one they went to sleep on.
|
||||
*/
|
||||
}
|
||||
|
||||
void i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
|
||||
void i915_request_unsubmit(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
unsigned long flags;
|
||||
|
@ -579,7 +586,7 @@ void i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
|
|||
/* Will be called from irq-context when using foreign fences. */
|
||||
spin_lock_irqsave(&engine->timeline->lock, flags);
|
||||
|
||||
__i915_gem_request_unsubmit(request);
|
||||
__i915_request_unsubmit(request);
|
||||
|
||||
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
||||
}
|
||||
|
@ -587,18 +594,19 @@ void i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
|
|||
static int __i915_sw_fence_call
|
||||
submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
|
||||
{
|
||||
struct drm_i915_gem_request *request =
|
||||
struct i915_request *request =
|
||||
container_of(fence, typeof(*request), submit);
|
||||
|
||||
switch (state) {
|
||||
case FENCE_COMPLETE:
|
||||
trace_i915_gem_request_submit(request);
|
||||
trace_i915_request_submit(request);
|
||||
/*
|
||||
* We need to serialize use of the submit_request() callback with its
|
||||
* hotplugging performed during an emergency i915_gem_set_wedged().
|
||||
* We use the RCU mechanism to mark the critical section in order to
|
||||
* force i915_gem_set_wedged() to wait until the submit_request() is
|
||||
* completed before proceeding.
|
||||
* We need to serialize use of the submit_request() callback
|
||||
* with its hotplugging performed during an emergency
|
||||
* i915_gem_set_wedged(). We use the RCU mechanism to mark the
|
||||
* critical section in order to force i915_gem_set_wedged() to
|
||||
* wait until the submit_request() is completed before
|
||||
* proceeding.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
request->engine->submit_request(request);
|
||||
|
@ -606,7 +614,7 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
|
|||
break;
|
||||
|
||||
case FENCE_FREE:
|
||||
i915_gem_request_put(request);
|
||||
i915_request_put(request);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -614,7 +622,7 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
|
|||
}
|
||||
|
||||
/**
|
||||
* i915_gem_request_alloc - allocate a request structure
|
||||
* i915_request_alloc - allocate a request structure
|
||||
*
|
||||
* @engine: engine that we wish to issue the request on.
|
||||
* @ctx: context that the request will be associated with.
|
||||
|
@ -622,31 +630,32 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
|
|||
* Returns a pointer to the allocated request if successful,
|
||||
* or an error code if not.
|
||||
*/
|
||||
struct drm_i915_gem_request *
|
||||
i915_gem_request_alloc(struct intel_engine_cs *engine,
|
||||
struct i915_gem_context *ctx)
|
||||
struct i915_request *
|
||||
i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
struct drm_i915_gem_request *req;
|
||||
struct drm_i915_private *i915 = engine->i915;
|
||||
struct i915_request *rq;
|
||||
struct intel_ring *ring;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
lockdep_assert_held(&i915->drm.struct_mutex);
|
||||
|
||||
/*
|
||||
* Preempt contexts are reserved for exclusive use to inject a
|
||||
* preemption context switch. They are never to be used for any trivial
|
||||
* request!
|
||||
*/
|
||||
GEM_BUG_ON(ctx == dev_priv->preempt_context);
|
||||
GEM_BUG_ON(ctx == i915->preempt_context);
|
||||
|
||||
/* ABI: Before userspace accesses the GPU (e.g. execbuffer), report
|
||||
/*
|
||||
* ABI: Before userspace accesses the GPU (e.g. execbuffer), report
|
||||
* EIO if the GPU is already wedged.
|
||||
*/
|
||||
if (i915_terminally_wedged(&dev_priv->gpu_error))
|
||||
if (i915_terminally_wedged(&i915->gpu_error))
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
/* Pinning the contexts may generate requests in order to acquire
|
||||
/*
|
||||
* Pinning the contexts may generate requests in order to acquire
|
||||
* GGTT space, so do this first before we reserve a seqno for
|
||||
* ourselves.
|
||||
*/
|
||||
|
@ -664,12 +673,13 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
|||
goto err_unreserve;
|
||||
|
||||
/* Move the oldest request to the slab-cache (if not in use!) */
|
||||
req = list_first_entry_or_null(&engine->timeline->requests,
|
||||
typeof(*req), link);
|
||||
if (req && i915_gem_request_completed(req))
|
||||
i915_gem_request_retire(req);
|
||||
rq = list_first_entry_or_null(&engine->timeline->requests,
|
||||
typeof(*rq), link);
|
||||
if (rq && i915_request_completed(rq))
|
||||
i915_request_retire(rq);
|
||||
|
||||
/* Beware: Dragons be flying overhead.
|
||||
/*
|
||||
* Beware: Dragons be flying overhead.
|
||||
*
|
||||
* We use RCU to look up requests in flight. The lookups may
|
||||
* race with the request being allocated from the slab freelist.
|
||||
|
@ -697,11 +707,11 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
|||
*
|
||||
* Do not use kmem_cache_zalloc() here!
|
||||
*/
|
||||
req = kmem_cache_alloc(dev_priv->requests,
|
||||
GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
|
||||
if (unlikely(!req)) {
|
||||
rq = kmem_cache_alloc(i915->requests,
|
||||
GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
|
||||
if (unlikely(!rq)) {
|
||||
/* Ratelimit ourselves to prevent oom from malicious clients */
|
||||
ret = i915_gem_wait_for_idle(dev_priv,
|
||||
ret = i915_gem_wait_for_idle(i915,
|
||||
I915_WAIT_LOCKED |
|
||||
I915_WAIT_INTERRUPTIBLE);
|
||||
if (ret)
|
||||
|
@ -715,55 +725,55 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
|||
* Having already penalized the client to stall, we spend
|
||||
* a little extra time to re-optimise page allocation.
|
||||
*/
|
||||
kmem_cache_shrink(dev_priv->requests);
|
||||
kmem_cache_shrink(i915->requests);
|
||||
rcu_barrier(); /* Recover the TYPESAFE_BY_RCU pages */
|
||||
|
||||
req = kmem_cache_alloc(dev_priv->requests, GFP_KERNEL);
|
||||
if (!req) {
|
||||
rq = kmem_cache_alloc(i915->requests, GFP_KERNEL);
|
||||
if (!rq) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unreserve;
|
||||
}
|
||||
}
|
||||
|
||||
req->timeline = i915_gem_context_lookup_timeline(ctx, engine);
|
||||
GEM_BUG_ON(req->timeline == engine->timeline);
|
||||
rq->timeline = i915_gem_context_lookup_timeline(ctx, engine);
|
||||
GEM_BUG_ON(rq->timeline == engine->timeline);
|
||||
|
||||
spin_lock_init(&req->lock);
|
||||
dma_fence_init(&req->fence,
|
||||
spin_lock_init(&rq->lock);
|
||||
dma_fence_init(&rq->fence,
|
||||
&i915_fence_ops,
|
||||
&req->lock,
|
||||
req->timeline->fence_context,
|
||||
timeline_get_seqno(req->timeline));
|
||||
&rq->lock,
|
||||
rq->timeline->fence_context,
|
||||
timeline_get_seqno(rq->timeline));
|
||||
|
||||
/* We bump the ref for the fence chain */
|
||||
i915_sw_fence_init(&i915_gem_request_get(req)->submit, submit_notify);
|
||||
init_waitqueue_head(&req->execute);
|
||||
i915_sw_fence_init(&i915_request_get(rq)->submit, submit_notify);
|
||||
init_waitqueue_head(&rq->execute);
|
||||
|
||||
i915_priotree_init(&req->priotree);
|
||||
i915_priotree_init(&rq->priotree);
|
||||
|
||||
INIT_LIST_HEAD(&req->active_list);
|
||||
req->i915 = dev_priv;
|
||||
req->engine = engine;
|
||||
req->ctx = ctx;
|
||||
req->ring = ring;
|
||||
INIT_LIST_HEAD(&rq->active_list);
|
||||
rq->i915 = i915;
|
||||
rq->engine = engine;
|
||||
rq->ctx = ctx;
|
||||
rq->ring = ring;
|
||||
|
||||
/* No zalloc, must clear what we need by hand */
|
||||
req->global_seqno = 0;
|
||||
req->signaling.wait.seqno = 0;
|
||||
req->file_priv = NULL;
|
||||
req->batch = NULL;
|
||||
req->capture_list = NULL;
|
||||
req->waitboost = false;
|
||||
rq->global_seqno = 0;
|
||||
rq->signaling.wait.seqno = 0;
|
||||
rq->file_priv = NULL;
|
||||
rq->batch = NULL;
|
||||
rq->capture_list = NULL;
|
||||
rq->waitboost = false;
|
||||
|
||||
/*
|
||||
* Reserve space in the ring buffer for all the commands required to
|
||||
* eventually emit this request. This is to guarantee that the
|
||||
* i915_add_request() call can't fail. Note that the reserve may need
|
||||
* i915_request_add() call can't fail. Note that the reserve may need
|
||||
* to be redone if the request is not actually submitted straight
|
||||
* away, e.g. because a GPU scheduler has deferred it.
|
||||
*/
|
||||
req->reserved_space = MIN_SPACE_FOR_ADD_REQUEST;
|
||||
GEM_BUG_ON(req->reserved_space < engine->emit_breadcrumb_sz);
|
||||
rq->reserved_space = MIN_SPACE_FOR_ADD_REQUEST;
|
||||
GEM_BUG_ON(rq->reserved_space < engine->emit_breadcrumb_sz);
|
||||
|
||||
/*
|
||||
* Record the position of the start of the request so that
|
||||
|
@ -771,30 +781,30 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
|||
* GPU processing the request, we never over-estimate the
|
||||
* position of the head.
|
||||
*/
|
||||
req->head = req->ring->emit;
|
||||
rq->head = rq->ring->emit;
|
||||
|
||||
/* Unconditionally invalidate GPU caches and TLBs. */
|
||||
ret = engine->emit_flush(req, EMIT_INVALIDATE);
|
||||
ret = engine->emit_flush(rq, EMIT_INVALIDATE);
|
||||
if (ret)
|
||||
goto err_unwind;
|
||||
|
||||
ret = engine->request_alloc(req);
|
||||
ret = engine->request_alloc(rq);
|
||||
if (ret)
|
||||
goto err_unwind;
|
||||
|
||||
/* Check that we didn't interrupt ourselves with a new request */
|
||||
GEM_BUG_ON(req->timeline->seqno != req->fence.seqno);
|
||||
return req;
|
||||
GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno);
|
||||
return rq;
|
||||
|
||||
err_unwind:
|
||||
req->ring->emit = req->head;
|
||||
rq->ring->emit = rq->head;
|
||||
|
||||
/* Make sure we didn't add ourselves to external state before freeing */
|
||||
GEM_BUG_ON(!list_empty(&req->active_list));
|
||||
GEM_BUG_ON(!list_empty(&req->priotree.signalers_list));
|
||||
GEM_BUG_ON(!list_empty(&req->priotree.waiters_list));
|
||||
GEM_BUG_ON(!list_empty(&rq->active_list));
|
||||
GEM_BUG_ON(!list_empty(&rq->priotree.signalers_list));
|
||||
GEM_BUG_ON(!list_empty(&rq->priotree.waiters_list));
|
||||
|
||||
kmem_cache_free(dev_priv->requests, req);
|
||||
kmem_cache_free(i915->requests, rq);
|
||||
err_unreserve:
|
||||
unreserve_engine(engine);
|
||||
err_unpin:
|
||||
|
@ -803,15 +813,14 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
|||
}
|
||||
|
||||
static int
|
||||
i915_gem_request_await_request(struct drm_i915_gem_request *to,
|
||||
struct drm_i915_gem_request *from)
|
||||
i915_request_await_request(struct i915_request *to, struct i915_request *from)
|
||||
{
|
||||
int ret;
|
||||
|
||||
GEM_BUG_ON(to == from);
|
||||
GEM_BUG_ON(to->timeline == from->timeline);
|
||||
|
||||
if (i915_gem_request_completed(from))
|
||||
if (i915_request_completed(from))
|
||||
return 0;
|
||||
|
||||
if (to->engine->schedule) {
|
||||
|
@ -834,7 +843,7 @@ i915_gem_request_await_request(struct drm_i915_gem_request *to,
|
|||
|
||||
GEM_BUG_ON(!from->engine->semaphore.signal);
|
||||
|
||||
seqno = i915_gem_request_global_seqno(from);
|
||||
seqno = i915_request_global_seqno(from);
|
||||
if (!seqno)
|
||||
goto await_dma_fence;
|
||||
|
||||
|
@ -858,14 +867,14 @@ i915_gem_request_await_request(struct drm_i915_gem_request *to,
|
|||
}
|
||||
|
||||
int
|
||||
i915_gem_request_await_dma_fence(struct drm_i915_gem_request *req,
|
||||
struct dma_fence *fence)
|
||||
i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
|
||||
{
|
||||
struct dma_fence **child = &fence;
|
||||
unsigned int nchild = 1;
|
||||
int ret;
|
||||
|
||||
/* Note that if the fence-array was created in signal-on-any mode,
|
||||
/*
|
||||
* Note that if the fence-array was created in signal-on-any mode,
|
||||
* we should *not* decompose it into its individual fences. However,
|
||||
* we don't currently store which mode the fence-array is operating
|
||||
* in. Fortunately, the only user of signal-on-any is private to
|
||||
|
@ -887,37 +896,36 @@ i915_gem_request_await_dma_fence(struct drm_i915_gem_request *req,
|
|||
|
||||
/*
|
||||
* Requests on the same timeline are explicitly ordered, along
|
||||
* with their dependencies, by i915_add_request() which ensures
|
||||
* with their dependencies, by i915_request_add() which ensures
|
||||
* that requests are submitted in-order through each ring.
|
||||
*/
|
||||
if (fence->context == req->fence.context)
|
||||
if (fence->context == rq->fence.context)
|
||||
continue;
|
||||
|
||||
/* Squash repeated waits to the same timelines */
|
||||
if (fence->context != req->i915->mm.unordered_timeline &&
|
||||
intel_timeline_sync_is_later(req->timeline, fence))
|
||||
if (fence->context != rq->i915->mm.unordered_timeline &&
|
||||
intel_timeline_sync_is_later(rq->timeline, fence))
|
||||
continue;
|
||||
|
||||
if (dma_fence_is_i915(fence))
|
||||
ret = i915_gem_request_await_request(req,
|
||||
to_request(fence));
|
||||
ret = i915_request_await_request(rq, to_request(fence));
|
||||
else
|
||||
ret = i915_sw_fence_await_dma_fence(&req->submit, fence,
|
||||
ret = i915_sw_fence_await_dma_fence(&rq->submit, fence,
|
||||
I915_FENCE_TIMEOUT,
|
||||
I915_FENCE_GFP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Record the latest fence used against each timeline */
|
||||
if (fence->context != req->i915->mm.unordered_timeline)
|
||||
intel_timeline_sync_set(req->timeline, fence);
|
||||
if (fence->context != rq->i915->mm.unordered_timeline)
|
||||
intel_timeline_sync_set(rq->timeline, fence);
|
||||
} while (--nchild);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_request_await_object - set this request to (async) wait upon a bo
|
||||
* i915_request_await_object - set this request to (async) wait upon a bo
|
||||
* @to: request we are wishing to use
|
||||
* @obj: object which may be in use on another ring.
|
||||
* @write: whether the wait is on behalf of a writer
|
||||
|
@ -937,9 +945,9 @@ i915_gem_request_await_dma_fence(struct drm_i915_gem_request *req,
|
|||
* Returns 0 if successful, else propagates up the lower layer error.
|
||||
*/
|
||||
int
|
||||
i915_gem_request_await_object(struct drm_i915_gem_request *to,
|
||||
struct drm_i915_gem_object *obj,
|
||||
bool write)
|
||||
i915_request_await_object(struct i915_request *to,
|
||||
struct drm_i915_gem_object *obj,
|
||||
bool write)
|
||||
{
|
||||
struct dma_fence *excl;
|
||||
int ret = 0;
|
||||
|
@ -954,7 +962,7 @@ i915_gem_request_await_object(struct drm_i915_gem_request *to,
|
|||
return ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = i915_gem_request_await_dma_fence(to, shared[i]);
|
||||
ret = i915_request_await_dma_fence(to, shared[i]);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
|
@ -970,7 +978,7 @@ i915_gem_request_await_object(struct drm_i915_gem_request *to,
|
|||
|
||||
if (excl) {
|
||||
if (ret == 0)
|
||||
ret = i915_gem_request_await_dma_fence(to, excl);
|
||||
ret = i915_request_await_dma_fence(to, excl);
|
||||
|
||||
dma_fence_put(excl);
|
||||
}
|
||||
|
@ -983,21 +991,21 @@ i915_gem_request_await_object(struct drm_i915_gem_request *to,
|
|||
* request is not being tracked for completion but the work itself is
|
||||
* going to happen on the hardware. This would be a Bad Thing(tm).
|
||||
*/
|
||||
void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
|
||||
void __i915_request_add(struct i915_request *request, bool flush_caches)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_ring *ring = request->ring;
|
||||
struct intel_timeline *timeline = request->timeline;
|
||||
struct drm_i915_gem_request *prev;
|
||||
struct i915_request *prev;
|
||||
u32 *cs;
|
||||
int err;
|
||||
|
||||
lockdep_assert_held(&request->i915->drm.struct_mutex);
|
||||
trace_i915_gem_request_add(request);
|
||||
trace_i915_request_add(request);
|
||||
|
||||
/*
|
||||
* Make sure that no request gazumped us - if it was allocated after
|
||||
* our i915_gem_request_alloc() and called __i915_add_request() before
|
||||
* our i915_request_alloc() and called __i915_request_add() before
|
||||
* us, the timeline will hold its seqno which is later than ours.
|
||||
*/
|
||||
GEM_BUG_ON(timeline->seqno != request->fence.seqno);
|
||||
|
@ -1042,7 +1050,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
|
|||
|
||||
prev = i915_gem_active_raw(&timeline->last_request,
|
||||
&request->i915->drm.struct_mutex);
|
||||
if (prev && !i915_gem_request_completed(prev)) {
|
||||
if (prev && !i915_request_completed(prev)) {
|
||||
i915_sw_fence_await_sw_fence(&request->submit, &prev->submit,
|
||||
&request->submitq);
|
||||
if (engine->schedule)
|
||||
|
@ -1097,15 +1105,16 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
|
|||
* work on behalf of others -- but instead we should benefit from
|
||||
* improved resource management. (Well, that's the theory at least.)
|
||||
*/
|
||||
if (prev && i915_gem_request_completed(prev))
|
||||
i915_gem_request_retire_upto(prev);
|
||||
if (prev && i915_request_completed(prev))
|
||||
i915_request_retire_upto(prev);
|
||||
}
|
||||
|
||||
static unsigned long local_clock_us(unsigned int *cpu)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
/* Cheaply and approximately convert from nanoseconds to microseconds.
|
||||
/*
|
||||
* Cheaply and approximately convert from nanoseconds to microseconds.
|
||||
* The result and subsequent calculations are also defined in the same
|
||||
* approximate microseconds units. The principal source of timing
|
||||
* error here is from the simple truncation.
|
||||
|
@ -1133,10 +1142,10 @@ static bool busywait_stop(unsigned long timeout, unsigned int cpu)
|
|||
return this_cpu != cpu;
|
||||
}
|
||||
|
||||
static bool __i915_spin_request(const struct drm_i915_gem_request *req,
|
||||
static bool __i915_spin_request(const struct i915_request *rq,
|
||||
u32 seqno, int state, unsigned long timeout_us)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
unsigned int irq, cpu;
|
||||
|
||||
GEM_BUG_ON(!seqno);
|
||||
|
@ -1155,7 +1164,8 @@ static bool __i915_spin_request(const struct drm_i915_gem_request *req,
|
|||
if (!i915_seqno_passed(intel_engine_get_seqno(engine), seqno - 1))
|
||||
return false;
|
||||
|
||||
/* When waiting for high frequency requests, e.g. during synchronous
|
||||
/*
|
||||
* When waiting for high frequency requests, e.g. during synchronous
|
||||
* rendering split between the CPU and GPU, the finite amount of time
|
||||
* required to set up the irq and wait upon it limits the response
|
||||
* rate. By busywaiting on the request completion for a short while we
|
||||
|
@ -1169,9 +1179,10 @@ static bool __i915_spin_request(const struct drm_i915_gem_request *req,
|
|||
timeout_us += local_clock_us(&cpu);
|
||||
do {
|
||||
if (i915_seqno_passed(intel_engine_get_seqno(engine), seqno))
|
||||
return seqno == i915_gem_request_global_seqno(req);
|
||||
return seqno == i915_request_global_seqno(rq);
|
||||
|
||||
/* Seqno are meant to be ordered *before* the interrupt. If
|
||||
/*
|
||||
* Seqno are meant to be ordered *before* the interrupt. If
|
||||
* we see an interrupt without a corresponding seqno advance,
|
||||
* assume we won't see one in the near future but require
|
||||
* the engine->seqno_barrier() to fixup coherency.
|
||||
|
@ -1191,7 +1202,7 @@ static bool __i915_spin_request(const struct drm_i915_gem_request *req,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool __i915_wait_request_check_and_reset(struct drm_i915_gem_request *request)
|
||||
static bool __i915_wait_request_check_and_reset(struct i915_request *request)
|
||||
{
|
||||
if (likely(!i915_reset_handoff(&request->i915->gpu_error)))
|
||||
return false;
|
||||
|
@ -1202,12 +1213,12 @@ static bool __i915_wait_request_check_and_reset(struct drm_i915_gem_request *req
|
|||
}
|
||||
|
||||
/**
|
||||
* i915_wait_request - wait until execution of request has finished
|
||||
* @req: the request to wait upon
|
||||
* i915_request_wait - wait until execution of request has finished
|
||||
* @rq: the request to wait upon
|
||||
* @flags: how to wait
|
||||
* @timeout: how long to wait in jiffies
|
||||
*
|
||||
* i915_wait_request() waits for the request to be completed, for a
|
||||
* i915_request_wait() waits for the request to be completed, for a
|
||||
* maximum of @timeout jiffies (with MAX_SCHEDULE_TIMEOUT implying an
|
||||
* unbounded wait).
|
||||
*
|
||||
|
@ -1220,13 +1231,13 @@ static bool __i915_wait_request_check_and_reset(struct drm_i915_gem_request *req
|
|||
* May return -EINTR is called with I915_WAIT_INTERRUPTIBLE and a signal is
|
||||
* pending before the request completes.
|
||||
*/
|
||||
long i915_wait_request(struct drm_i915_gem_request *req,
|
||||
long i915_request_wait(struct i915_request *rq,
|
||||
unsigned int flags,
|
||||
long timeout)
|
||||
{
|
||||
const int state = flags & I915_WAIT_INTERRUPTIBLE ?
|
||||
TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
|
||||
wait_queue_head_t *errq = &req->i915->gpu_error.wait_queue;
|
||||
wait_queue_head_t *errq = &rq->i915->gpu_error.wait_queue;
|
||||
DEFINE_WAIT_FUNC(reset, default_wake_function);
|
||||
DEFINE_WAIT_FUNC(exec, default_wake_function);
|
||||
struct intel_wait wait;
|
||||
|
@ -1234,33 +1245,33 @@ long i915_wait_request(struct drm_i915_gem_request *req,
|
|||
might_sleep();
|
||||
#if IS_ENABLED(CONFIG_LOCKDEP)
|
||||
GEM_BUG_ON(debug_locks &&
|
||||
!!lockdep_is_held(&req->i915->drm.struct_mutex) !=
|
||||
!!lockdep_is_held(&rq->i915->drm.struct_mutex) !=
|
||||
!!(flags & I915_WAIT_LOCKED));
|
||||
#endif
|
||||
GEM_BUG_ON(timeout < 0);
|
||||
|
||||
if (i915_gem_request_completed(req))
|
||||
if (i915_request_completed(rq))
|
||||
return timeout;
|
||||
|
||||
if (!timeout)
|
||||
return -ETIME;
|
||||
|
||||
trace_i915_gem_request_wait_begin(req, flags);
|
||||
trace_i915_request_wait_begin(rq, flags);
|
||||
|
||||
add_wait_queue(&req->execute, &exec);
|
||||
add_wait_queue(&rq->execute, &exec);
|
||||
if (flags & I915_WAIT_LOCKED)
|
||||
add_wait_queue(errq, &reset);
|
||||
|
||||
intel_wait_init(&wait, req);
|
||||
intel_wait_init(&wait, rq);
|
||||
|
||||
restart:
|
||||
do {
|
||||
set_current_state(state);
|
||||
if (intel_wait_update_request(&wait, req))
|
||||
if (intel_wait_update_request(&wait, rq))
|
||||
break;
|
||||
|
||||
if (flags & I915_WAIT_LOCKED &&
|
||||
__i915_wait_request_check_and_reset(req))
|
||||
__i915_wait_request_check_and_reset(rq))
|
||||
continue;
|
||||
|
||||
if (signal_pending_state(state, current)) {
|
||||
|
@ -1277,22 +1288,23 @@ long i915_wait_request(struct drm_i915_gem_request *req,
|
|||
} while (1);
|
||||
|
||||
GEM_BUG_ON(!intel_wait_has_seqno(&wait));
|
||||
GEM_BUG_ON(!i915_sw_fence_signaled(&req->submit));
|
||||
GEM_BUG_ON(!i915_sw_fence_signaled(&rq->submit));
|
||||
|
||||
/* Optimistic short spin before touching IRQs */
|
||||
if (__i915_spin_request(req, wait.seqno, state, 5))
|
||||
if (__i915_spin_request(rq, wait.seqno, state, 5))
|
||||
goto complete;
|
||||
|
||||
set_current_state(state);
|
||||
if (intel_engine_add_wait(req->engine, &wait))
|
||||
/* In order to check that we haven't missed the interrupt
|
||||
if (intel_engine_add_wait(rq->engine, &wait))
|
||||
/*
|
||||
* In order to check that we haven't missed the interrupt
|
||||
* as we enabled it, we need to kick ourselves to do a
|
||||
* coherent check on the seqno before we sleep.
|
||||
*/
|
||||
goto wakeup;
|
||||
|
||||
if (flags & I915_WAIT_LOCKED)
|
||||
__i915_wait_request_check_and_reset(req);
|
||||
__i915_wait_request_check_and_reset(rq);
|
||||
|
||||
for (;;) {
|
||||
if (signal_pending_state(state, current)) {
|
||||
|
@ -1308,21 +1320,23 @@ long i915_wait_request(struct drm_i915_gem_request *req,
|
|||
timeout = io_schedule_timeout(timeout);
|
||||
|
||||
if (intel_wait_complete(&wait) &&
|
||||
intel_wait_check_request(&wait, req))
|
||||
intel_wait_check_request(&wait, rq))
|
||||
break;
|
||||
|
||||
set_current_state(state);
|
||||
|
||||
wakeup:
|
||||
/* Carefully check if the request is complete, giving time
|
||||
/*
|
||||
* Carefully check if the request is complete, giving time
|
||||
* for the seqno to be visible following the interrupt.
|
||||
* We also have to check in case we are kicked by the GPU
|
||||
* reset in order to drop the struct_mutex.
|
||||
*/
|
||||
if (__i915_request_irq_complete(req))
|
||||
if (__i915_request_irq_complete(rq))
|
||||
break;
|
||||
|
||||
/* If the GPU is hung, and we hold the lock, reset the GPU
|
||||
/*
|
||||
* If the GPU is hung, and we hold the lock, reset the GPU
|
||||
* and then check for completion. On a full reset, the engine's
|
||||
* HW seqno will be advanced passed us and we are complete.
|
||||
* If we do a partial reset, we have to wait for the GPU to
|
||||
|
@ -1333,33 +1347,33 @@ long i915_wait_request(struct drm_i915_gem_request *req,
|
|||
* itself, or indirectly by recovering the GPU).
|
||||
*/
|
||||
if (flags & I915_WAIT_LOCKED &&
|
||||
__i915_wait_request_check_and_reset(req))
|
||||
__i915_wait_request_check_and_reset(rq))
|
||||
continue;
|
||||
|
||||
/* Only spin if we know the GPU is processing this request */
|
||||
if (__i915_spin_request(req, wait.seqno, state, 2))
|
||||
if (__i915_spin_request(rq, wait.seqno, state, 2))
|
||||
break;
|
||||
|
||||
if (!intel_wait_check_request(&wait, req)) {
|
||||
intel_engine_remove_wait(req->engine, &wait);
|
||||
if (!intel_wait_check_request(&wait, rq)) {
|
||||
intel_engine_remove_wait(rq->engine, &wait);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
intel_engine_remove_wait(req->engine, &wait);
|
||||
intel_engine_remove_wait(rq->engine, &wait);
|
||||
complete:
|
||||
__set_current_state(TASK_RUNNING);
|
||||
if (flags & I915_WAIT_LOCKED)
|
||||
remove_wait_queue(errq, &reset);
|
||||
remove_wait_queue(&req->execute, &exec);
|
||||
trace_i915_gem_request_wait_end(req);
|
||||
remove_wait_queue(&rq->execute, &exec);
|
||||
trace_i915_request_wait_end(rq);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
static void engine_retire_requests(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *request, *next;
|
||||
struct i915_request *request, *next;
|
||||
u32 seqno = intel_engine_get_seqno(engine);
|
||||
LIST_HEAD(retire);
|
||||
|
||||
|
@ -1374,24 +1388,24 @@ static void engine_retire_requests(struct intel_engine_cs *engine)
|
|||
spin_unlock_irq(&engine->timeline->lock);
|
||||
|
||||
list_for_each_entry_safe(request, next, &retire, link)
|
||||
i915_gem_request_retire(request);
|
||||
i915_request_retire(request);
|
||||
}
|
||||
|
||||
void i915_gem_retire_requests(struct drm_i915_private *dev_priv)
|
||||
void i915_retire_requests(struct drm_i915_private *i915)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
enum intel_engine_id id;
|
||||
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
lockdep_assert_held(&i915->drm.struct_mutex);
|
||||
|
||||
if (!dev_priv->gt.active_requests)
|
||||
if (!i915->gt.active_requests)
|
||||
return;
|
||||
|
||||
for_each_engine(engine, dev_priv, id)
|
||||
for_each_engine(engine, i915, id)
|
||||
engine_retire_requests(engine);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
|
||||
#include "selftests/mock_request.c"
|
||||
#include "selftests/i915_gem_request.c"
|
||||
#include "selftests/i915_request.c"
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2008-2015 Intel Corporation
|
||||
* Copyright © 2008-2018 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -22,8 +22,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef I915_GEM_REQUEST_H
|
||||
#define I915_GEM_REQUEST_H
|
||||
#ifndef I915_REQUEST_H
|
||||
#define I915_REQUEST_H
|
||||
|
||||
#include <linux/dma-fence.h>
|
||||
|
||||
|
@ -34,18 +34,18 @@
|
|||
|
||||
struct drm_file;
|
||||
struct drm_i915_gem_object;
|
||||
struct drm_i915_gem_request;
|
||||
struct i915_request;
|
||||
|
||||
struct intel_wait {
|
||||
struct rb_node node;
|
||||
struct task_struct *tsk;
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
u32 seqno;
|
||||
};
|
||||
|
||||
struct intel_signal_node {
|
||||
struct rb_node node;
|
||||
struct intel_wait wait;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
struct i915_dependency {
|
||||
|
@ -57,7 +57,12 @@ struct i915_dependency {
|
|||
#define I915_DEPENDENCY_ALLOC BIT(0)
|
||||
};
|
||||
|
||||
/* Requests exist in a complex web of interdependencies. Each request
|
||||
/*
|
||||
* "People assume that time is a strict progression of cause to effect, but
|
||||
* actually, from a nonlinear, non-subjective viewpoint, it's more like a big
|
||||
* ball of wibbly-wobbly, timey-wimey ... stuff." -The Doctor, 2015
|
||||
*
|
||||
* Requests exist in a complex web of interdependencies. Each request
|
||||
* has to wait for some other request to complete before it is ready to be run
|
||||
* (e.g. we have to wait until the pixels have been rendering into a texture
|
||||
* before we can copy from it). We track the readiness of a request in terms
|
||||
|
@ -81,8 +86,8 @@ enum {
|
|||
I915_PRIORITY_INVALID = INT_MIN
|
||||
};
|
||||
|
||||
struct i915_gem_capture_list {
|
||||
struct i915_gem_capture_list *next;
|
||||
struct i915_capture_list {
|
||||
struct i915_capture_list *next;
|
||||
struct i915_vma *vma;
|
||||
};
|
||||
|
||||
|
@ -106,7 +111,7 @@ struct i915_gem_capture_list {
|
|||
*
|
||||
* The requests are reference counted.
|
||||
*/
|
||||
struct drm_i915_gem_request {
|
||||
struct i915_request {
|
||||
struct dma_fence fence;
|
||||
spinlock_t lock;
|
||||
|
||||
|
@ -120,7 +125,7 @@ struct drm_i915_gem_request {
|
|||
* it persists while any request is linked to it. Requests themselves
|
||||
* are also refcounted, so the request will only be freed when the last
|
||||
* reference to it is dismissed, and the code in
|
||||
* i915_gem_request_free() will then decrement the refcount on the
|
||||
* i915_request_free() will then decrement the refcount on the
|
||||
* context.
|
||||
*/
|
||||
struct i915_gem_context *ctx;
|
||||
|
@ -129,7 +134,8 @@ struct drm_i915_gem_request {
|
|||
struct intel_timeline *timeline;
|
||||
struct intel_signal_node signaling;
|
||||
|
||||
/* Fences for the various phases in the request's lifetime.
|
||||
/*
|
||||
* Fences for the various phases in the request's lifetime.
|
||||
*
|
||||
* The submit fence is used to await upon all of the request's
|
||||
* dependencies. When it is signaled, the request is ready to run.
|
||||
|
@ -139,7 +145,8 @@ struct drm_i915_gem_request {
|
|||
wait_queue_entry_t submitq;
|
||||
wait_queue_head_t execute;
|
||||
|
||||
/* A list of everyone we wait upon, and everyone who waits upon us.
|
||||
/*
|
||||
* A list of everyone we wait upon, and everyone who waits upon us.
|
||||
* Even though we will not be submitted to the hardware before the
|
||||
* submit fence is signaled (it waits for all external events as well
|
||||
* as our own requests), the scheduler still needs to know the
|
||||
|
@ -150,7 +157,8 @@ struct drm_i915_gem_request {
|
|||
struct i915_priotree priotree;
|
||||
struct i915_dependency dep;
|
||||
|
||||
/** GEM sequence number associated with this request on the
|
||||
/**
|
||||
* GEM sequence number associated with this request on the
|
||||
* global execution timeline. It is zero when the request is not
|
||||
* on the HW queue (i.e. not on the engine timeline list).
|
||||
* Its value is guarded by the timeline spinlock.
|
||||
|
@ -180,12 +188,13 @@ struct drm_i915_gem_request {
|
|||
* error state dump only).
|
||||
*/
|
||||
struct i915_vma *batch;
|
||||
/** Additional buffers requested by userspace to be captured upon
|
||||
/**
|
||||
* Additional buffers requested by userspace to be captured upon
|
||||
* a GPU hang. The vma/obj on this list are protected by their
|
||||
* active reference - all objects on this list must also be
|
||||
* on the active_list (of their final request).
|
||||
*/
|
||||
struct i915_gem_capture_list *capture_list;
|
||||
struct i915_capture_list *capture_list;
|
||||
struct list_head active_list;
|
||||
|
||||
/** Time at which this request was emitted, in jiffies. */
|
||||
|
@ -213,40 +222,40 @@ static inline bool dma_fence_is_i915(const struct dma_fence *fence)
|
|||
return fence->ops == &i915_fence_ops;
|
||||
}
|
||||
|
||||
struct drm_i915_gem_request * __must_check
|
||||
i915_gem_request_alloc(struct intel_engine_cs *engine,
|
||||
struct i915_gem_context *ctx);
|
||||
void i915_gem_request_retire_upto(struct drm_i915_gem_request *req);
|
||||
struct i915_request * __must_check
|
||||
i915_request_alloc(struct intel_engine_cs *engine,
|
||||
struct i915_gem_context *ctx);
|
||||
void i915_request_retire_upto(struct i915_request *rq);
|
||||
|
||||
static inline struct drm_i915_gem_request *
|
||||
static inline struct i915_request *
|
||||
to_request(struct dma_fence *fence)
|
||||
{
|
||||
/* We assume that NULL fence/request are interoperable */
|
||||
BUILD_BUG_ON(offsetof(struct drm_i915_gem_request, fence) != 0);
|
||||
BUILD_BUG_ON(offsetof(struct i915_request, fence) != 0);
|
||||
GEM_BUG_ON(fence && !dma_fence_is_i915(fence));
|
||||
return container_of(fence, struct drm_i915_gem_request, fence);
|
||||
return container_of(fence, struct i915_request, fence);
|
||||
}
|
||||
|
||||
static inline struct drm_i915_gem_request *
|
||||
i915_gem_request_get(struct drm_i915_gem_request *req)
|
||||
static inline struct i915_request *
|
||||
i915_request_get(struct i915_request *rq)
|
||||
{
|
||||
return to_request(dma_fence_get(&req->fence));
|
||||
return to_request(dma_fence_get(&rq->fence));
|
||||
}
|
||||
|
||||
static inline struct drm_i915_gem_request *
|
||||
i915_gem_request_get_rcu(struct drm_i915_gem_request *req)
|
||||
static inline struct i915_request *
|
||||
i915_request_get_rcu(struct i915_request *rq)
|
||||
{
|
||||
return to_request(dma_fence_get_rcu(&req->fence));
|
||||
return to_request(dma_fence_get_rcu(&rq->fence));
|
||||
}
|
||||
|
||||
static inline void
|
||||
i915_gem_request_put(struct drm_i915_gem_request *req)
|
||||
i915_request_put(struct i915_request *rq)
|
||||
{
|
||||
dma_fence_put(&req->fence);
|
||||
dma_fence_put(&rq->fence);
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_request_global_seqno - report the current global seqno
|
||||
* i915_request_global_seqno - report the current global seqno
|
||||
* @request - the request
|
||||
*
|
||||
* A request is assigned a global seqno only when it is on the hardware
|
||||
|
@ -264,34 +273,28 @@ i915_gem_request_put(struct drm_i915_gem_request *req)
|
|||
* after the read, it is indeed complete).
|
||||
*/
|
||||
static u32
|
||||
i915_gem_request_global_seqno(const struct drm_i915_gem_request *request)
|
||||
i915_request_global_seqno(const struct i915_request *request)
|
||||
{
|
||||
return READ_ONCE(request->global_seqno);
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_request_await_object(struct drm_i915_gem_request *to,
|
||||
int i915_request_await_object(struct i915_request *to,
|
||||
struct drm_i915_gem_object *obj,
|
||||
bool write);
|
||||
int i915_gem_request_await_dma_fence(struct drm_i915_gem_request *req,
|
||||
struct dma_fence *fence);
|
||||
int i915_request_await_dma_fence(struct i915_request *rq,
|
||||
struct dma_fence *fence);
|
||||
|
||||
void __i915_add_request(struct drm_i915_gem_request *req, bool flush_caches);
|
||||
#define i915_add_request(req) \
|
||||
__i915_add_request(req, false)
|
||||
void __i915_request_add(struct i915_request *rq, bool flush_caches);
|
||||
#define i915_request_add(rq) \
|
||||
__i915_request_add(rq, false)
|
||||
|
||||
void __i915_gem_request_submit(struct drm_i915_gem_request *request);
|
||||
void i915_gem_request_submit(struct drm_i915_gem_request *request);
|
||||
void __i915_request_submit(struct i915_request *request);
|
||||
void i915_request_submit(struct i915_request *request);
|
||||
|
||||
void __i915_gem_request_unsubmit(struct drm_i915_gem_request *request);
|
||||
void i915_gem_request_unsubmit(struct drm_i915_gem_request *request);
|
||||
void __i915_request_unsubmit(struct i915_request *request);
|
||||
void i915_request_unsubmit(struct i915_request *request);
|
||||
|
||||
struct intel_rps_client;
|
||||
#define NO_WAITBOOST ERR_PTR(-1)
|
||||
#define IS_RPS_CLIENT(p) (!IS_ERR(p))
|
||||
#define IS_RPS_USER(p) (!IS_ERR_OR_NULL(p))
|
||||
|
||||
long i915_wait_request(struct drm_i915_gem_request *req,
|
||||
long i915_request_wait(struct i915_request *rq,
|
||||
unsigned int flags,
|
||||
long timeout)
|
||||
__attribute__((nonnull(1)));
|
||||
|
@ -310,47 +313,48 @@ static inline bool i915_seqno_passed(u32 seq1, u32 seq2)
|
|||
}
|
||||
|
||||
static inline bool
|
||||
__i915_gem_request_completed(const struct drm_i915_gem_request *req, u32 seqno)
|
||||
__i915_request_completed(const struct i915_request *rq, u32 seqno)
|
||||
{
|
||||
GEM_BUG_ON(!seqno);
|
||||
return i915_seqno_passed(intel_engine_get_seqno(req->engine), seqno) &&
|
||||
seqno == i915_gem_request_global_seqno(req);
|
||||
return i915_seqno_passed(intel_engine_get_seqno(rq->engine), seqno) &&
|
||||
seqno == i915_request_global_seqno(rq);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
i915_gem_request_completed(const struct drm_i915_gem_request *req)
|
||||
static inline bool i915_request_completed(const struct i915_request *rq)
|
||||
{
|
||||
u32 seqno;
|
||||
|
||||
seqno = i915_gem_request_global_seqno(req);
|
||||
seqno = i915_request_global_seqno(rq);
|
||||
if (!seqno)
|
||||
return false;
|
||||
|
||||
return __i915_gem_request_completed(req, seqno);
|
||||
return __i915_request_completed(rq, seqno);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
i915_gem_request_started(const struct drm_i915_gem_request *req)
|
||||
static inline bool i915_request_started(const struct i915_request *rq)
|
||||
{
|
||||
u32 seqno;
|
||||
|
||||
seqno = i915_gem_request_global_seqno(req);
|
||||
seqno = i915_request_global_seqno(rq);
|
||||
if (!seqno)
|
||||
return false;
|
||||
|
||||
return i915_seqno_passed(intel_engine_get_seqno(req->engine),
|
||||
return i915_seqno_passed(intel_engine_get_seqno(rq->engine),
|
||||
seqno - 1);
|
||||
}
|
||||
|
||||
static inline bool i915_priotree_signaled(const struct i915_priotree *pt)
|
||||
{
|
||||
const struct drm_i915_gem_request *rq =
|
||||
container_of(pt, const struct drm_i915_gem_request, priotree);
|
||||
const struct i915_request *rq =
|
||||
container_of(pt, const struct i915_request, priotree);
|
||||
|
||||
return i915_gem_request_completed(rq);
|
||||
return i915_request_completed(rq);
|
||||
}
|
||||
|
||||
/* We treat requests as fences. This is not be to confused with our
|
||||
void i915_retire_requests(struct drm_i915_private *i915);
|
||||
|
||||
/*
|
||||
* We treat requests as fences. This is not be to confused with our
|
||||
* "fence registers" but pipeline synchronisation objects ala GL_ARB_sync.
|
||||
* We use the fences to synchronize access from the CPU with activity on the
|
||||
* GPU, for example, we should not rewrite an object's PTE whilst the GPU
|
||||
|
@ -380,16 +384,16 @@ static inline bool i915_priotree_signaled(const struct i915_priotree *pt)
|
|||
struct i915_gem_active;
|
||||
|
||||
typedef void (*i915_gem_retire_fn)(struct i915_gem_active *,
|
||||
struct drm_i915_gem_request *);
|
||||
struct i915_request *);
|
||||
|
||||
struct i915_gem_active {
|
||||
struct drm_i915_gem_request __rcu *request;
|
||||
struct i915_request __rcu *request;
|
||||
struct list_head link;
|
||||
i915_gem_retire_fn retire;
|
||||
};
|
||||
|
||||
void i915_gem_retire_noop(struct i915_gem_active *,
|
||||
struct drm_i915_gem_request *request);
|
||||
struct i915_request *request);
|
||||
|
||||
/**
|
||||
* init_request_active - prepares the activity tracker for use
|
||||
|
@ -421,7 +425,7 @@ init_request_active(struct i915_gem_active *active,
|
|||
*/
|
||||
static inline void
|
||||
i915_gem_active_set(struct i915_gem_active *active,
|
||||
struct drm_i915_gem_request *request)
|
||||
struct i915_request *request)
|
||||
{
|
||||
list_move(&active->link, &request->active_list);
|
||||
rcu_assign_pointer(active->request, request);
|
||||
|
@ -446,10 +450,11 @@ i915_gem_active_set_retire_fn(struct i915_gem_active *active,
|
|||
active->retire = fn ?: i915_gem_retire_noop;
|
||||
}
|
||||
|
||||
static inline struct drm_i915_gem_request *
|
||||
static inline struct i915_request *
|
||||
__i915_gem_active_peek(const struct i915_gem_active *active)
|
||||
{
|
||||
/* Inside the error capture (running with the driver in an unknown
|
||||
/*
|
||||
* Inside the error capture (running with the driver in an unknown
|
||||
* state), we want to bend the rules slightly (a lot).
|
||||
*
|
||||
* Work is in progress to make it safer, in the meantime this keeps
|
||||
|
@ -466,7 +471,7 @@ __i915_gem_active_peek(const struct i915_gem_active *active)
|
|||
* It does not obtain a reference on the request for the caller, so the caller
|
||||
* must hold struct_mutex.
|
||||
*/
|
||||
static inline struct drm_i915_gem_request *
|
||||
static inline struct i915_request *
|
||||
i915_gem_active_raw(const struct i915_gem_active *active, struct mutex *mutex)
|
||||
{
|
||||
return rcu_dereference_protected(active->request,
|
||||
|
@ -481,13 +486,13 @@ i915_gem_active_raw(const struct i915_gem_active *active, struct mutex *mutex)
|
|||
* still active, or NULL. It does not obtain a reference on the request
|
||||
* for the caller, so the caller must hold struct_mutex.
|
||||
*/
|
||||
static inline struct drm_i915_gem_request *
|
||||
static inline struct i915_request *
|
||||
i915_gem_active_peek(const struct i915_gem_active *active, struct mutex *mutex)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
|
||||
request = i915_gem_active_raw(active, mutex);
|
||||
if (!request || i915_gem_request_completed(request))
|
||||
if (!request || i915_request_completed(request))
|
||||
return NULL;
|
||||
|
||||
return request;
|
||||
|
@ -500,10 +505,10 @@ i915_gem_active_peek(const struct i915_gem_active *active, struct mutex *mutex)
|
|||
* i915_gem_active_get() returns a reference to the active request, or NULL
|
||||
* if the active tracker is idle. The caller must hold struct_mutex.
|
||||
*/
|
||||
static inline struct drm_i915_gem_request *
|
||||
static inline struct i915_request *
|
||||
i915_gem_active_get(const struct i915_gem_active *active, struct mutex *mutex)
|
||||
{
|
||||
return i915_gem_request_get(i915_gem_active_peek(active, mutex));
|
||||
return i915_request_get(i915_gem_active_peek(active, mutex));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -514,10 +519,11 @@ i915_gem_active_get(const struct i915_gem_active *active, struct mutex *mutex)
|
|||
* if the active tracker is idle. The caller must hold the RCU read lock, but
|
||||
* the returned pointer is safe to use outside of RCU.
|
||||
*/
|
||||
static inline struct drm_i915_gem_request *
|
||||
static inline struct i915_request *
|
||||
__i915_gem_active_get_rcu(const struct i915_gem_active *active)
|
||||
{
|
||||
/* Performing a lockless retrieval of the active request is super
|
||||
/*
|
||||
* Performing a lockless retrieval of the active request is super
|
||||
* tricky. SLAB_TYPESAFE_BY_RCU merely guarantees that the backing
|
||||
* slab of request objects will not be freed whilst we hold the
|
||||
* RCU read lock. It does not guarantee that the request itself
|
||||
|
@ -525,13 +531,13 @@ __i915_gem_active_get_rcu(const struct i915_gem_active *active)
|
|||
*
|
||||
* Thread A Thread B
|
||||
*
|
||||
* req = active.request
|
||||
* retire(req) -> free(req);
|
||||
* (req is now first on the slab freelist)
|
||||
* rq = active.request
|
||||
* retire(rq) -> free(rq);
|
||||
* (rq is now first on the slab freelist)
|
||||
* active.request = NULL
|
||||
*
|
||||
* req = new submission on a new object
|
||||
* ref(req)
|
||||
* rq = new submission on a new object
|
||||
* ref(rq)
|
||||
*
|
||||
* To prevent the request from being reused whilst the caller
|
||||
* uses it, we take a reference like normal. Whilst acquiring
|
||||
|
@ -560,32 +566,34 @@ __i915_gem_active_get_rcu(const struct i915_gem_active *active)
|
|||
*
|
||||
* It is then imperative that we do not zero the request on
|
||||
* reallocation, so that we can chase the dangling pointers!
|
||||
* See i915_gem_request_alloc().
|
||||
* See i915_request_alloc().
|
||||
*/
|
||||
do {
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
|
||||
request = rcu_dereference(active->request);
|
||||
if (!request || i915_gem_request_completed(request))
|
||||
if (!request || i915_request_completed(request))
|
||||
return NULL;
|
||||
|
||||
/* An especially silly compiler could decide to recompute the
|
||||
* result of i915_gem_request_completed, more specifically
|
||||
/*
|
||||
* An especially silly compiler could decide to recompute the
|
||||
* result of i915_request_completed, more specifically
|
||||
* re-emit the load for request->fence.seqno. A race would catch
|
||||
* a later seqno value, which could flip the result from true to
|
||||
* false. Which means part of the instructions below might not
|
||||
* be executed, while later on instructions are executed. Due to
|
||||
* barriers within the refcounting the inconsistency can't reach
|
||||
* past the call to i915_gem_request_get_rcu, but not executing
|
||||
* that while still executing i915_gem_request_put() creates
|
||||
* past the call to i915_request_get_rcu, but not executing
|
||||
* that while still executing i915_request_put() creates
|
||||
* havoc enough. Prevent this with a compiler barrier.
|
||||
*/
|
||||
barrier();
|
||||
|
||||
request = i915_gem_request_get_rcu(request);
|
||||
request = i915_request_get_rcu(request);
|
||||
|
||||
/* What stops the following rcu_access_pointer() from occurring
|
||||
* before the above i915_gem_request_get_rcu()? If we were
|
||||
/*
|
||||
* What stops the following rcu_access_pointer() from occurring
|
||||
* before the above i915_request_get_rcu()? If we were
|
||||
* to read the value before pausing to get the reference to
|
||||
* the request, we may not notice a change in the active
|
||||
* tracker.
|
||||
|
@ -599,9 +607,9 @@ __i915_gem_active_get_rcu(const struct i915_gem_active *active)
|
|||
* compiler.
|
||||
*
|
||||
* The atomic operation at the heart of
|
||||
* i915_gem_request_get_rcu(), see dma_fence_get_rcu(), is
|
||||
* i915_request_get_rcu(), see dma_fence_get_rcu(), is
|
||||
* atomic_inc_not_zero() which is only a full memory barrier
|
||||
* when successful. That is, if i915_gem_request_get_rcu()
|
||||
* when successful. That is, if i915_request_get_rcu()
|
||||
* returns the request (and so with the reference counted
|
||||
* incremented) then the following read for rcu_access_pointer()
|
||||
* must occur after the atomic operation and so confirm
|
||||
|
@ -613,7 +621,7 @@ __i915_gem_active_get_rcu(const struct i915_gem_active *active)
|
|||
if (!request || request == rcu_access_pointer(active->request))
|
||||
return rcu_pointer_handoff(request);
|
||||
|
||||
i915_gem_request_put(request);
|
||||
i915_request_put(request);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
|
@ -625,12 +633,12 @@ __i915_gem_active_get_rcu(const struct i915_gem_active *active)
|
|||
* or NULL if the active tracker is idle. The reference is obtained under RCU,
|
||||
* so no locking is required by the caller.
|
||||
*
|
||||
* The reference should be freed with i915_gem_request_put().
|
||||
* The reference should be freed with i915_request_put().
|
||||
*/
|
||||
static inline struct drm_i915_gem_request *
|
||||
static inline struct i915_request *
|
||||
i915_gem_active_get_unlocked(const struct i915_gem_active *active)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
|
||||
rcu_read_lock();
|
||||
request = __i915_gem_active_get_rcu(active);
|
||||
|
@ -670,7 +678,7 @@ i915_gem_active_isset(const struct i915_gem_active *active)
|
|||
* can then wait upon the request, and afterwards release our reference,
|
||||
* free of any locking.
|
||||
*
|
||||
* This function wraps i915_wait_request(), see it for the full details on
|
||||
* This function wraps i915_request_wait(), see it for the full details on
|
||||
* the arguments.
|
||||
*
|
||||
* Returns 0 if successful, or a negative error code.
|
||||
|
@ -678,13 +686,13 @@ i915_gem_active_isset(const struct i915_gem_active *active)
|
|||
static inline int
|
||||
i915_gem_active_wait(const struct i915_gem_active *active, unsigned int flags)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
long ret = 0;
|
||||
|
||||
request = i915_gem_active_get_unlocked(active);
|
||||
if (request) {
|
||||
ret = i915_wait_request(request, flags, MAX_SCHEDULE_TIMEOUT);
|
||||
i915_gem_request_put(request);
|
||||
ret = i915_request_wait(request, flags, MAX_SCHEDULE_TIMEOUT);
|
||||
i915_request_put(request);
|
||||
}
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
|
@ -703,14 +711,14 @@ static inline int __must_check
|
|||
i915_gem_active_retire(struct i915_gem_active *active,
|
||||
struct mutex *mutex)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
long ret;
|
||||
|
||||
request = i915_gem_active_raw(active, mutex);
|
||||
if (!request)
|
||||
return 0;
|
||||
|
||||
ret = i915_wait_request(request,
|
||||
ret = i915_request_wait(request,
|
||||
I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
|
@ -727,4 +735,4 @@ i915_gem_active_retire(struct i915_gem_active *active,
|
|||
#define for_each_active(mask, idx) \
|
||||
for (; mask ? idx = ffs(mask) - 1, 1 : 0; mask &= ~BIT(idx))
|
||||
|
||||
#endif /* I915_GEM_REQUEST_H */
|
||||
#endif /* I915_REQUEST_H */
|
|
@ -586,8 +586,7 @@ TRACE_EVENT(i915_gem_evict_vm,
|
|||
);
|
||||
|
||||
TRACE_EVENT(i915_gem_ring_sync_to,
|
||||
TP_PROTO(struct drm_i915_gem_request *to,
|
||||
struct drm_i915_gem_request *from),
|
||||
TP_PROTO(struct i915_request *to, struct i915_request *from),
|
||||
TP_ARGS(to, from),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
|
@ -610,9 +609,9 @@ TRACE_EVENT(i915_gem_ring_sync_to,
|
|||
__entry->seqno)
|
||||
);
|
||||
|
||||
TRACE_EVENT(i915_gem_request_queue,
|
||||
TP_PROTO(struct drm_i915_gem_request *req, u32 flags),
|
||||
TP_ARGS(req, flags),
|
||||
TRACE_EVENT(i915_request_queue,
|
||||
TP_PROTO(struct i915_request *rq, u32 flags),
|
||||
TP_ARGS(rq, flags),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, dev)
|
||||
|
@ -624,11 +623,11 @@ TRACE_EVENT(i915_gem_request_queue,
|
|||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = req->i915->drm.primary->index;
|
||||
__entry->hw_id = req->ctx->hw_id;
|
||||
__entry->ring = req->engine->id;
|
||||
__entry->ctx = req->fence.context;
|
||||
__entry->seqno = req->fence.seqno;
|
||||
__entry->dev = rq->i915->drm.primary->index;
|
||||
__entry->hw_id = rq->ctx->hw_id;
|
||||
__entry->ring = rq->engine->id;
|
||||
__entry->ctx = rq->fence.context;
|
||||
__entry->seqno = rq->fence.seqno;
|
||||
__entry->flags = flags;
|
||||
),
|
||||
|
||||
|
@ -637,9 +636,9 @@ TRACE_EVENT(i915_gem_request_queue,
|
|||
__entry->seqno, __entry->flags)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(i915_gem_request,
|
||||
TP_PROTO(struct drm_i915_gem_request *req),
|
||||
TP_ARGS(req),
|
||||
DECLARE_EVENT_CLASS(i915_request,
|
||||
TP_PROTO(struct i915_request *rq),
|
||||
TP_ARGS(rq),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, dev)
|
||||
|
@ -651,12 +650,12 @@ DECLARE_EVENT_CLASS(i915_gem_request,
|
|||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = req->i915->drm.primary->index;
|
||||
__entry->hw_id = req->ctx->hw_id;
|
||||
__entry->ring = req->engine->id;
|
||||
__entry->ctx = req->fence.context;
|
||||
__entry->seqno = req->fence.seqno;
|
||||
__entry->global = req->global_seqno;
|
||||
__entry->dev = rq->i915->drm.primary->index;
|
||||
__entry->hw_id = rq->ctx->hw_id;
|
||||
__entry->ring = rq->engine->id;
|
||||
__entry->ctx = rq->fence.context;
|
||||
__entry->seqno = rq->fence.seqno;
|
||||
__entry->global = rq->global_seqno;
|
||||
),
|
||||
|
||||
TP_printk("dev=%u, hw_id=%u, ring=%u, ctx=%u, seqno=%u, global=%u",
|
||||
|
@ -664,26 +663,25 @@ DECLARE_EVENT_CLASS(i915_gem_request,
|
|||
__entry->seqno, __entry->global)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(i915_gem_request, i915_gem_request_add,
|
||||
TP_PROTO(struct drm_i915_gem_request *req),
|
||||
TP_ARGS(req)
|
||||
DEFINE_EVENT(i915_request, i915_request_add,
|
||||
TP_PROTO(struct i915_request *rq),
|
||||
TP_ARGS(rq)
|
||||
);
|
||||
|
||||
#if defined(CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS)
|
||||
DEFINE_EVENT(i915_gem_request, i915_gem_request_submit,
|
||||
TP_PROTO(struct drm_i915_gem_request *req),
|
||||
TP_ARGS(req)
|
||||
DEFINE_EVENT(i915_request, i915_request_submit,
|
||||
TP_PROTO(struct i915_request *rq),
|
||||
TP_ARGS(rq)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(i915_gem_request, i915_gem_request_execute,
|
||||
TP_PROTO(struct drm_i915_gem_request *req),
|
||||
TP_ARGS(req)
|
||||
DEFINE_EVENT(i915_request, i915_request_execute,
|
||||
TP_PROTO(struct i915_request *rq),
|
||||
TP_ARGS(rq)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(i915_gem_request_hw,
|
||||
TP_PROTO(struct drm_i915_gem_request *req,
|
||||
unsigned int port),
|
||||
TP_ARGS(req, port),
|
||||
DECLARE_EVENT_CLASS(i915_request_hw,
|
||||
TP_PROTO(struct i915_request *rq, unsigned int port),
|
||||
TP_ARGS(rq, port),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, dev)
|
||||
|
@ -696,14 +694,14 @@ DECLARE_EVENT_CLASS(i915_gem_request_hw,
|
|||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = req->i915->drm.primary->index;
|
||||
__entry->hw_id = req->ctx->hw_id;
|
||||
__entry->ring = req->engine->id;
|
||||
__entry->ctx = req->fence.context;
|
||||
__entry->seqno = req->fence.seqno;
|
||||
__entry->global_seqno = req->global_seqno;
|
||||
__entry->port = port;
|
||||
),
|
||||
__entry->dev = rq->i915->drm.primary->index;
|
||||
__entry->hw_id = rq->ctx->hw_id;
|
||||
__entry->ring = rq->engine->id;
|
||||
__entry->ctx = rq->fence.context;
|
||||
__entry->seqno = rq->fence.seqno;
|
||||
__entry->global_seqno = rq->global_seqno;
|
||||
__entry->port = port;
|
||||
),
|
||||
|
||||
TP_printk("dev=%u, hw_id=%u, ring=%u, ctx=%u, seqno=%u, global=%u, port=%u",
|
||||
__entry->dev, __entry->hw_id, __entry->ring,
|
||||
|
@ -711,34 +709,34 @@ DECLARE_EVENT_CLASS(i915_gem_request_hw,
|
|||
__entry->global_seqno, __entry->port)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(i915_gem_request_hw, i915_gem_request_in,
|
||||
TP_PROTO(struct drm_i915_gem_request *req, unsigned int port),
|
||||
TP_ARGS(req, port)
|
||||
DEFINE_EVENT(i915_request_hw, i915_request_in,
|
||||
TP_PROTO(struct i915_request *rq, unsigned int port),
|
||||
TP_ARGS(rq, port)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(i915_gem_request, i915_gem_request_out,
|
||||
TP_PROTO(struct drm_i915_gem_request *req),
|
||||
TP_ARGS(req)
|
||||
DEFINE_EVENT(i915_request, i915_request_out,
|
||||
TP_PROTO(struct i915_request *rq),
|
||||
TP_ARGS(rq)
|
||||
);
|
||||
#else
|
||||
#if !defined(TRACE_HEADER_MULTI_READ)
|
||||
static inline void
|
||||
trace_i915_gem_request_submit(struct drm_i915_gem_request *req)
|
||||
trace_i915_request_submit(struct i915_request *rq)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
trace_i915_gem_request_execute(struct drm_i915_gem_request *req)
|
||||
trace_i915_request_execute(struct i915_request *rq)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
trace_i915_gem_request_in(struct drm_i915_gem_request *req, unsigned int port)
|
||||
trace_i915_request_in(struct i915_request *rq, unsigned int port)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
trace_i915_gem_request_out(struct drm_i915_gem_request *req)
|
||||
trace_i915_request_out(struct i915_request *rq)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
@ -767,14 +765,14 @@ TRACE_EVENT(intel_engine_notify,
|
|||
__entry->waiters)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(i915_gem_request, i915_gem_request_retire,
|
||||
TP_PROTO(struct drm_i915_gem_request *req),
|
||||
TP_ARGS(req)
|
||||
DEFINE_EVENT(i915_request, i915_request_retire,
|
||||
TP_PROTO(struct i915_request *rq),
|
||||
TP_ARGS(rq)
|
||||
);
|
||||
|
||||
TRACE_EVENT(i915_gem_request_wait_begin,
|
||||
TP_PROTO(struct drm_i915_gem_request *req, unsigned int flags),
|
||||
TP_ARGS(req, flags),
|
||||
TRACE_EVENT(i915_request_wait_begin,
|
||||
TP_PROTO(struct i915_request *rq, unsigned int flags),
|
||||
TP_ARGS(rq, flags),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, dev)
|
||||
|
@ -793,12 +791,12 @@ TRACE_EVENT(i915_gem_request_wait_begin,
|
|||
* less desirable.
|
||||
*/
|
||||
TP_fast_assign(
|
||||
__entry->dev = req->i915->drm.primary->index;
|
||||
__entry->hw_id = req->ctx->hw_id;
|
||||
__entry->ring = req->engine->id;
|
||||
__entry->ctx = req->fence.context;
|
||||
__entry->seqno = req->fence.seqno;
|
||||
__entry->global = req->global_seqno;
|
||||
__entry->dev = rq->i915->drm.primary->index;
|
||||
__entry->hw_id = rq->ctx->hw_id;
|
||||
__entry->ring = rq->engine->id;
|
||||
__entry->ctx = rq->fence.context;
|
||||
__entry->seqno = rq->fence.seqno;
|
||||
__entry->global = rq->global_seqno;
|
||||
__entry->flags = flags;
|
||||
),
|
||||
|
||||
|
@ -808,9 +806,9 @@ TRACE_EVENT(i915_gem_request_wait_begin,
|
|||
!!(__entry->flags & I915_WAIT_LOCKED), __entry->flags)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
|
||||
TP_PROTO(struct drm_i915_gem_request *req),
|
||||
TP_ARGS(req)
|
||||
DEFINE_EVENT(i915_request, i915_request_wait_end,
|
||||
TP_PROTO(struct i915_request *rq),
|
||||
TP_ARGS(rq)
|
||||
);
|
||||
|
||||
TRACE_EVENT(i915_flip_request,
|
||||
|
|
|
@ -31,8 +31,7 @@
|
|||
#include <drm/drm_gem.h>
|
||||
|
||||
static void
|
||||
i915_vma_retire(struct i915_gem_active *active,
|
||||
struct drm_i915_gem_request *rq)
|
||||
i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq)
|
||||
{
|
||||
const unsigned int idx = rq->engine->id;
|
||||
struct i915_vma *vma =
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
#include "i915_gem_gtt.h"
|
||||
#include "i915_gem_fence_reg.h"
|
||||
#include "i915_gem_object.h"
|
||||
#include "i915_gem_request.h"
|
||||
|
||||
#include "i915_request.h"
|
||||
|
||||
enum i915_cache_level;
|
||||
|
||||
|
|
|
@ -168,17 +168,21 @@ static void irq_enable(struct intel_engine_cs *engine)
|
|||
set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);
|
||||
|
||||
/* Caller disables interrupts */
|
||||
spin_lock(&engine->i915->irq_lock);
|
||||
engine->irq_enable(engine);
|
||||
spin_unlock(&engine->i915->irq_lock);
|
||||
if (engine->irq_enable) {
|
||||
spin_lock(&engine->i915->irq_lock);
|
||||
engine->irq_enable(engine);
|
||||
spin_unlock(&engine->i915->irq_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void irq_disable(struct intel_engine_cs *engine)
|
||||
{
|
||||
/* Caller disables interrupts */
|
||||
spin_lock(&engine->i915->irq_lock);
|
||||
engine->irq_disable(engine);
|
||||
spin_unlock(&engine->i915->irq_lock);
|
||||
if (engine->irq_disable) {
|
||||
spin_lock(&engine->i915->irq_lock);
|
||||
engine->irq_disable(engine);
|
||||
spin_unlock(&engine->i915->irq_lock);
|
||||
}
|
||||
}
|
||||
|
||||
void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
|
||||
|
@ -243,6 +247,8 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
|
|||
spin_unlock(&b->irq_lock);
|
||||
|
||||
rbtree_postorder_for_each_entry_safe(wait, n, &b->waiters, node) {
|
||||
GEM_BUG_ON(!i915_seqno_passed(intel_engine_get_seqno(engine),
|
||||
wait->seqno));
|
||||
RB_CLEAR_NODE(&wait->node);
|
||||
wake_up_process(wait->tsk);
|
||||
}
|
||||
|
@ -336,7 +342,8 @@ static inline void __intel_breadcrumbs_finish(struct intel_breadcrumbs *b,
|
|||
lockdep_assert_held(&b->rb_lock);
|
||||
GEM_BUG_ON(b->irq_wait == wait);
|
||||
|
||||
/* This request is completed, so remove it from the tree, mark it as
|
||||
/*
|
||||
* This request is completed, so remove it from the tree, mark it as
|
||||
* complete, and *then* wake up the associated task. N.B. when the
|
||||
* task wakes up, it will find the empty rb_node, discern that it
|
||||
* has already been removed from the tree and skip the serialisation
|
||||
|
@ -347,7 +354,8 @@ static inline void __intel_breadcrumbs_finish(struct intel_breadcrumbs *b,
|
|||
rb_erase(&wait->node, &b->waiters);
|
||||
RB_CLEAR_NODE(&wait->node);
|
||||
|
||||
wake_up_process(wait->tsk); /* implicit smp_wmb() */
|
||||
if (wait->tsk->state != TASK_RUNNING)
|
||||
wake_up_process(wait->tsk); /* implicit smp_wmb() */
|
||||
}
|
||||
|
||||
static inline void __intel_breadcrumbs_next(struct intel_engine_cs *engine,
|
||||
|
@ -588,23 +596,6 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine,
|
|||
spin_unlock_irq(&b->rb_lock);
|
||||
}
|
||||
|
||||
static bool signal_complete(const struct drm_i915_gem_request *request)
|
||||
{
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Carefully check if the request is complete, giving time for the
|
||||
* seqno to be visible or if the GPU hung.
|
||||
*/
|
||||
return __i915_request_irq_complete(request);
|
||||
}
|
||||
|
||||
static struct drm_i915_gem_request *to_signaler(struct rb_node *rb)
|
||||
{
|
||||
return rb_entry(rb, struct drm_i915_gem_request, signaling.node);
|
||||
}
|
||||
|
||||
static void signaler_set_rtpriority(void)
|
||||
{
|
||||
struct sched_param param = { .sched_priority = 1 };
|
||||
|
@ -612,78 +603,26 @@ static void signaler_set_rtpriority(void)
|
|||
sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m);
|
||||
}
|
||||
|
||||
static void __intel_engine_remove_signal(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request)
|
||||
{
|
||||
struct intel_breadcrumbs *b = &engine->breadcrumbs;
|
||||
|
||||
lockdep_assert_held(&b->rb_lock);
|
||||
|
||||
/*
|
||||
* Wake up all other completed waiters and select the
|
||||
* next bottom-half for the next user interrupt.
|
||||
*/
|
||||
__intel_engine_remove_wait(engine, &request->signaling.wait);
|
||||
|
||||
/*
|
||||
* Find the next oldest signal. Note that as we have
|
||||
* not been holding the lock, another client may
|
||||
* have installed an even older signal than the one
|
||||
* we just completed - so double check we are still
|
||||
* the oldest before picking the next one.
|
||||
*/
|
||||
if (request->signaling.wait.seqno) {
|
||||
if (request == rcu_access_pointer(b->first_signal)) {
|
||||
struct rb_node *rb = rb_next(&request->signaling.node);
|
||||
rcu_assign_pointer(b->first_signal,
|
||||
rb ? to_signaler(rb) : NULL);
|
||||
}
|
||||
|
||||
rb_erase(&request->signaling.node, &b->signals);
|
||||
request->signaling.wait.seqno = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct drm_i915_gem_request *
|
||||
get_first_signal_rcu(struct intel_breadcrumbs *b)
|
||||
{
|
||||
/*
|
||||
* See the big warnings for i915_gem_active_get_rcu() and similarly
|
||||
* for dma_fence_get_rcu_safe() that explain the intricacies involved
|
||||
* here with defeating CPU/compiler speculation and enforcing
|
||||
* the required memory barriers.
|
||||
*/
|
||||
do {
|
||||
struct drm_i915_gem_request *request;
|
||||
|
||||
request = rcu_dereference(b->first_signal);
|
||||
if (request)
|
||||
request = i915_gem_request_get_rcu(request);
|
||||
|
||||
barrier();
|
||||
|
||||
if (!request || request == rcu_access_pointer(b->first_signal))
|
||||
return rcu_pointer_handoff(request);
|
||||
|
||||
i915_gem_request_put(request);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static int intel_breadcrumbs_signaler(void *arg)
|
||||
{
|
||||
struct intel_engine_cs *engine = arg;
|
||||
struct intel_breadcrumbs *b = &engine->breadcrumbs;
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *rq, *n;
|
||||
|
||||
/* Install ourselves with high priority to reduce signalling latency */
|
||||
signaler_set_rtpriority();
|
||||
|
||||
do {
|
||||
bool do_schedule = true;
|
||||
LIST_HEAD(list);
|
||||
u32 seqno;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (list_empty(&b->signals))
|
||||
goto sleep;
|
||||
|
||||
/* We are either woken up by the interrupt bottom-half,
|
||||
/*
|
||||
* We are either woken up by the interrupt bottom-half,
|
||||
* or by a client adding a new signaller. In both cases,
|
||||
* the GPU seqno may have advanced beyond our oldest signal.
|
||||
* If it has, propagate the signal, remove the waiter and
|
||||
|
@ -691,25 +630,45 @@ static int intel_breadcrumbs_signaler(void *arg)
|
|||
* need to wait for a new interrupt from the GPU or for
|
||||
* a new client.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
request = get_first_signal_rcu(b);
|
||||
rcu_read_unlock();
|
||||
if (signal_complete(request)) {
|
||||
if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
|
||||
&request->fence.flags)) {
|
||||
local_bh_disable();
|
||||
dma_fence_signal(&request->fence);
|
||||
GEM_BUG_ON(!i915_gem_request_completed(request));
|
||||
local_bh_enable(); /* kick start the tasklets */
|
||||
}
|
||||
seqno = intel_engine_get_seqno(engine);
|
||||
|
||||
if (READ_ONCE(request->signaling.wait.seqno)) {
|
||||
spin_lock_irq(&b->rb_lock);
|
||||
__intel_engine_remove_signal(engine, request);
|
||||
spin_unlock_irq(&b->rb_lock);
|
||||
}
|
||||
spin_lock_irq(&b->rb_lock);
|
||||
list_for_each_entry_safe(rq, n, &b->signals, signaling.link) {
|
||||
u32 this = rq->signaling.wait.seqno;
|
||||
|
||||
/* If the engine is saturated we may be continually
|
||||
GEM_BUG_ON(!rq->signaling.wait.seqno);
|
||||
|
||||
if (!i915_seqno_passed(seqno, this))
|
||||
break;
|
||||
|
||||
if (likely(this == i915_request_global_seqno(rq))) {
|
||||
__intel_engine_remove_wait(engine,
|
||||
&rq->signaling.wait);
|
||||
|
||||
rq->signaling.wait.seqno = 0;
|
||||
__list_del_entry(&rq->signaling.link);
|
||||
|
||||
if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
|
||||
&rq->fence.flags)) {
|
||||
list_add_tail(&rq->signaling.link,
|
||||
&list);
|
||||
i915_request_get(rq);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&b->rb_lock);
|
||||
|
||||
if (!list_empty(&list)) {
|
||||
local_bh_disable();
|
||||
list_for_each_entry_safe(rq, n, &list, signaling.link) {
|
||||
dma_fence_signal(&rq->fence);
|
||||
GEM_BUG_ON(!i915_request_completed(rq));
|
||||
i915_request_put(rq);
|
||||
}
|
||||
local_bh_enable(); /* kick start the tasklets */
|
||||
|
||||
/*
|
||||
* If the engine is saturated we may be continually
|
||||
* processing completed requests. This angers the
|
||||
* NMI watchdog if we never let anything else
|
||||
* have access to the CPU. Let's pretend to be nice
|
||||
|
@ -718,9 +677,19 @@ static int intel_breadcrumbs_signaler(void *arg)
|
|||
*/
|
||||
do_schedule = need_resched();
|
||||
}
|
||||
i915_gem_request_put(request);
|
||||
|
||||
if (unlikely(do_schedule)) {
|
||||
/* Before we sleep, check for a missed seqno */
|
||||
if (current->state & TASK_NORMAL &&
|
||||
!list_empty(&b->signals) &&
|
||||
engine->irq_seqno_barrier &&
|
||||
test_and_clear_bit(ENGINE_IRQ_BREADCRUMB,
|
||||
&engine->irq_posted)) {
|
||||
engine->irq_seqno_barrier(engine);
|
||||
intel_engine_wakeup(engine);
|
||||
}
|
||||
|
||||
sleep:
|
||||
if (kthread_should_park())
|
||||
kthread_parkme();
|
||||
|
||||
|
@ -735,14 +704,40 @@ static int intel_breadcrumbs_signaler(void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void intel_engine_enable_signaling(struct drm_i915_gem_request *request,
|
||||
bool wakeup)
|
||||
static void insert_signal(struct intel_breadcrumbs *b,
|
||||
struct i915_request *request,
|
||||
const u32 seqno)
|
||||
{
|
||||
struct i915_request *iter;
|
||||
|
||||
lockdep_assert_held(&b->rb_lock);
|
||||
|
||||
/*
|
||||
* A reasonable assumption is that we are called to add signals
|
||||
* in sequence, as the requests are submitted for execution and
|
||||
* assigned a global_seqno. This will be the case for the majority
|
||||
* of internally generated signals (inter-engine signaling).
|
||||
*
|
||||
* Out of order waiters triggering random signaling enabling will
|
||||
* be more problematic, but hopefully rare enough and the list
|
||||
* small enough that the O(N) insertion sort is not an issue.
|
||||
*/
|
||||
|
||||
list_for_each_entry_reverse(iter, &b->signals, signaling.link)
|
||||
if (i915_seqno_passed(seqno, iter->signaling.wait.seqno))
|
||||
break;
|
||||
|
||||
list_add(&request->signaling.link, &iter->signaling.link);
|
||||
}
|
||||
|
||||
void intel_engine_enable_signaling(struct i915_request *request, bool wakeup)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_breadcrumbs *b = &engine->breadcrumbs;
|
||||
u32 seqno;
|
||||
|
||||
/* Note that we may be called from an interrupt handler on another
|
||||
/*
|
||||
* Note that we may be called from an interrupt handler on another
|
||||
* device (e.g. nouveau signaling a fence completion causing us
|
||||
* to submit a request, and so enable signaling). As such,
|
||||
* we need to make sure that all other users of b->rb_lock protect
|
||||
|
@ -753,18 +748,17 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request,
|
|||
GEM_BUG_ON(!irqs_disabled());
|
||||
lockdep_assert_held(&request->lock);
|
||||
|
||||
seqno = i915_gem_request_global_seqno(request);
|
||||
if (!seqno)
|
||||
seqno = i915_request_global_seqno(request);
|
||||
if (!seqno) /* will be enabled later upon execution */
|
||||
return;
|
||||
|
||||
spin_lock(&b->rb_lock);
|
||||
|
||||
GEM_BUG_ON(request->signaling.wait.seqno);
|
||||
request->signaling.wait.tsk = b->signaler;
|
||||
request->signaling.wait.request = request;
|
||||
request->signaling.wait.seqno = seqno;
|
||||
|
||||
/* First add ourselves into the list of waiters, but register our
|
||||
/*
|
||||
* Add ourselves into the list of waiters, but registering our
|
||||
* bottom-half as the signaller thread. As per usual, only the oldest
|
||||
* waiter (not just signaller) is tasked as the bottom-half waking
|
||||
* up all completed waiters after the user interrupt.
|
||||
|
@ -772,58 +766,31 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request,
|
|||
* If we are the oldest waiter, enable the irq (after which we
|
||||
* must double check that the seqno did not complete).
|
||||
*/
|
||||
spin_lock(&b->rb_lock);
|
||||
insert_signal(b, request, seqno);
|
||||
wakeup &= __intel_engine_add_wait(engine, &request->signaling.wait);
|
||||
|
||||
if (!__i915_gem_request_completed(request, seqno)) {
|
||||
struct rb_node *parent, **p;
|
||||
bool first;
|
||||
|
||||
/* Now insert ourselves into the retirement ordered list of
|
||||
* signals on this engine. We track the oldest seqno as that
|
||||
* will be the first signal to complete.
|
||||
*/
|
||||
parent = NULL;
|
||||
first = true;
|
||||
p = &b->signals.rb_node;
|
||||
while (*p) {
|
||||
parent = *p;
|
||||
if (i915_seqno_passed(seqno,
|
||||
to_signaler(parent)->signaling.wait.seqno)) {
|
||||
p = &parent->rb_right;
|
||||
first = false;
|
||||
} else {
|
||||
p = &parent->rb_left;
|
||||
}
|
||||
}
|
||||
rb_link_node(&request->signaling.node, parent, p);
|
||||
rb_insert_color(&request->signaling.node, &b->signals);
|
||||
if (first)
|
||||
rcu_assign_pointer(b->first_signal, request);
|
||||
} else {
|
||||
__intel_engine_remove_wait(engine, &request->signaling.wait);
|
||||
request->signaling.wait.seqno = 0;
|
||||
wakeup = false;
|
||||
}
|
||||
|
||||
spin_unlock(&b->rb_lock);
|
||||
|
||||
if (wakeup)
|
||||
wake_up_process(b->signaler);
|
||||
}
|
||||
|
||||
void intel_engine_cancel_signaling(struct drm_i915_gem_request *request)
|
||||
void intel_engine_cancel_signaling(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_breadcrumbs *b = &engine->breadcrumbs;
|
||||
|
||||
GEM_BUG_ON(!irqs_disabled());
|
||||
lockdep_assert_held(&request->lock);
|
||||
|
||||
if (READ_ONCE(request->signaling.wait.seqno)) {
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_breadcrumbs *b = &engine->breadcrumbs;
|
||||
if (!READ_ONCE(request->signaling.wait.seqno))
|
||||
return;
|
||||
|
||||
spin_lock(&b->rb_lock);
|
||||
__intel_engine_remove_signal(engine, request);
|
||||
spin_unlock(&b->rb_lock);
|
||||
}
|
||||
spin_lock(&b->rb_lock);
|
||||
__intel_engine_remove_wait(engine, &request->signaling.wait);
|
||||
if (fetch_and_zero(&request->signaling.wait.seqno))
|
||||
__list_del_entry(&request->signaling.link);
|
||||
spin_unlock(&b->rb_lock);
|
||||
}
|
||||
|
||||
int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
|
||||
|
@ -837,6 +804,8 @@ int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
|
|||
timer_setup(&b->fake_irq, intel_breadcrumbs_fake_irq, 0);
|
||||
timer_setup(&b->hangcheck, intel_breadcrumbs_hangcheck, 0);
|
||||
|
||||
INIT_LIST_HEAD(&b->signals);
|
||||
|
||||
/* Spawn a thread to provide a common bottom-half for all signals.
|
||||
* As this is an asynchronous interface we cannot steal the current
|
||||
* task for handling the bottom-half to the user interrupt, therefore
|
||||
|
@ -896,8 +865,7 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
|
|||
/* The engines should be idle and all requests accounted for! */
|
||||
WARN_ON(READ_ONCE(b->irq_wait));
|
||||
WARN_ON(!RB_EMPTY_ROOT(&b->waiters));
|
||||
WARN_ON(rcu_access_pointer(b->first_signal));
|
||||
WARN_ON(!RB_EMPTY_ROOT(&b->signals));
|
||||
WARN_ON(!list_empty(&b->signals));
|
||||
|
||||
if (!IS_ERR_OR_NULL(b->signaler))
|
||||
kthread_stop(b->signaler);
|
||||
|
@ -905,28 +873,6 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
|
|||
cancel_fake_irq(engine);
|
||||
}
|
||||
|
||||
bool intel_breadcrumbs_busy(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct intel_breadcrumbs *b = &engine->breadcrumbs;
|
||||
bool busy = false;
|
||||
|
||||
spin_lock_irq(&b->rb_lock);
|
||||
|
||||
if (b->irq_wait) {
|
||||
wake_up_process(b->irq_wait->tsk);
|
||||
busy = true;
|
||||
}
|
||||
|
||||
if (rcu_access_pointer(b->first_signal)) {
|
||||
wake_up_process(b->signaler);
|
||||
busy = true;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&b->rb_lock);
|
||||
|
||||
return busy;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
|
||||
#include "selftests/intel_breadcrumbs.c"
|
||||
#endif
|
||||
|
|
|
@ -66,13 +66,13 @@
|
|||
* of the CTM coefficient and we write the value from bit 3. We also round the
|
||||
* value.
|
||||
*/
|
||||
#define I9XX_CSC_COEFF_FP(coeff, fbits) \
|
||||
#define ILK_CSC_COEFF_FP(coeff, fbits) \
|
||||
(clamp_val(((coeff) >> (32 - (fbits) - 3)) + 4, 0, 0xfff) & 0xff8)
|
||||
|
||||
#define I9XX_CSC_COEFF_LIMITED_RANGE \
|
||||
I9XX_CSC_COEFF_FP(CTM_COEFF_LIMITED_RANGE, 9)
|
||||
#define I9XX_CSC_COEFF_1_0 \
|
||||
((7 << 12) | I9XX_CSC_COEFF_FP(CTM_COEFF_1_0, 8))
|
||||
#define ILK_CSC_COEFF_LIMITED_RANGE \
|
||||
ILK_CSC_COEFF_FP(CTM_COEFF_LIMITED_RANGE, 9)
|
||||
#define ILK_CSC_COEFF_1_0 \
|
||||
((7 << 12) | ILK_CSC_COEFF_FP(CTM_COEFF_1_0, 8))
|
||||
|
||||
static bool crtc_state_is_legacy_gamma(struct drm_crtc_state *state)
|
||||
{
|
||||
|
@ -84,30 +84,31 @@ static bool crtc_state_is_legacy_gamma(struct drm_crtc_state *state)
|
|||
|
||||
/*
|
||||
* When using limited range, multiply the matrix given by userspace by
|
||||
* the matrix that we would use for the limited range. We do the
|
||||
* multiplication in U2.30 format.
|
||||
* the matrix that we would use for the limited range.
|
||||
*/
|
||||
static void ctm_mult_by_limited(uint64_t *result, int64_t *input)
|
||||
static u64 *ctm_mult_by_limited(u64 *result, const u64 *input)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
result[i] = 0;
|
||||
for (i = 0; i < 9; i++) {
|
||||
u64 user_coeff = input[i];
|
||||
u32 limited_coeff = CTM_COEFF_LIMITED_RANGE;
|
||||
u32 abs_coeff = clamp_val(CTM_COEFF_ABS(user_coeff), 0,
|
||||
CTM_COEFF_4_0 - 1) >> 2;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
int64_t user_coeff = input[i * 3 + i];
|
||||
uint64_t limited_coeff = CTM_COEFF_LIMITED_RANGE >> 2;
|
||||
uint64_t abs_coeff = clamp_val(CTM_COEFF_ABS(user_coeff),
|
||||
0,
|
||||
CTM_COEFF_4_0 - 1) >> 2;
|
||||
|
||||
result[i * 3 + i] = (limited_coeff * abs_coeff) >> 27;
|
||||
if (CTM_COEFF_NEGATIVE(user_coeff))
|
||||
result[i * 3 + i] |= CTM_COEFF_SIGN;
|
||||
/*
|
||||
* By scaling every co-efficient with limited range (16-235)
|
||||
* vs full range (0-255) the final o/p will be scaled down to
|
||||
* fit in the limited range supported by the panel.
|
||||
*/
|
||||
result[i] = mul_u32_u32(limited_coeff, abs_coeff) >> 30;
|
||||
result[i] |= user_coeff & CTM_COEFF_SIGN;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void i9xx_load_ycbcr_conversion_matrix(struct intel_crtc *intel_crtc)
|
||||
static void ilk_load_ycbcr_conversion_matrix(struct intel_crtc *intel_crtc)
|
||||
{
|
||||
int pipe = intel_crtc->pipe;
|
||||
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
|
||||
|
@ -131,8 +132,7 @@ static void i9xx_load_ycbcr_conversion_matrix(struct intel_crtc *intel_crtc)
|
|||
I915_WRITE(PIPE_CSC_MODE(pipe), 0);
|
||||
}
|
||||
|
||||
/* Set up the pipe CSC unit. */
|
||||
static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
||||
static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_crtc *crtc = crtc_state->crtc;
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
||||
|
@ -140,21 +140,28 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
|||
int i, pipe = intel_crtc->pipe;
|
||||
uint16_t coeffs[9] = { 0, };
|
||||
struct intel_crtc_state *intel_crtc_state = to_intel_crtc_state(crtc_state);
|
||||
bool limited_color_range = false;
|
||||
|
||||
/*
|
||||
* FIXME if there's a gamma LUT after the CSC, we should
|
||||
* do the range compression using the gamma LUT instead.
|
||||
*/
|
||||
if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv))
|
||||
limited_color_range = intel_crtc_state->limited_color_range;
|
||||
|
||||
if (intel_crtc_state->ycbcr420) {
|
||||
i9xx_load_ycbcr_conversion_matrix(intel_crtc);
|
||||
ilk_load_ycbcr_conversion_matrix(intel_crtc);
|
||||
return;
|
||||
} else if (crtc_state->ctm) {
|
||||
struct drm_color_ctm *ctm =
|
||||
(struct drm_color_ctm *)crtc_state->ctm->data;
|
||||
uint64_t input[9] = { 0, };
|
||||
const u64 *input;
|
||||
u64 temp[9];
|
||||
|
||||
if (intel_crtc_state->limited_color_range) {
|
||||
ctm_mult_by_limited(input, ctm->matrix);
|
||||
} else {
|
||||
for (i = 0; i < ARRAY_SIZE(input); i++)
|
||||
input[i] = ctm->matrix[i];
|
||||
}
|
||||
if (limited_color_range)
|
||||
input = ctm_mult_by_limited(temp, ctm->matrix);
|
||||
else
|
||||
input = ctm->matrix;
|
||||
|
||||
/*
|
||||
* Convert fixed point S31.32 input to format supported by the
|
||||
|
@ -175,21 +182,21 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
|||
|
||||
if (abs_coeff < CTM_COEFF_0_125)
|
||||
coeffs[i] |= (3 << 12) |
|
||||
I9XX_CSC_COEFF_FP(abs_coeff, 12);
|
||||
ILK_CSC_COEFF_FP(abs_coeff, 12);
|
||||
else if (abs_coeff < CTM_COEFF_0_25)
|
||||
coeffs[i] |= (2 << 12) |
|
||||
I9XX_CSC_COEFF_FP(abs_coeff, 11);
|
||||
ILK_CSC_COEFF_FP(abs_coeff, 11);
|
||||
else if (abs_coeff < CTM_COEFF_0_5)
|
||||
coeffs[i] |= (1 << 12) |
|
||||
I9XX_CSC_COEFF_FP(abs_coeff, 10);
|
||||
ILK_CSC_COEFF_FP(abs_coeff, 10);
|
||||
else if (abs_coeff < CTM_COEFF_1_0)
|
||||
coeffs[i] |= I9XX_CSC_COEFF_FP(abs_coeff, 9);
|
||||
coeffs[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9);
|
||||
else if (abs_coeff < CTM_COEFF_2_0)
|
||||
coeffs[i] |= (7 << 12) |
|
||||
I9XX_CSC_COEFF_FP(abs_coeff, 8);
|
||||
ILK_CSC_COEFF_FP(abs_coeff, 8);
|
||||
else
|
||||
coeffs[i] |= (6 << 12) |
|
||||
I9XX_CSC_COEFF_FP(abs_coeff, 7);
|
||||
ILK_CSC_COEFF_FP(abs_coeff, 7);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
@ -201,11 +208,11 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
|||
* into consideration.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (intel_crtc_state->limited_color_range)
|
||||
if (limited_color_range)
|
||||
coeffs[i * 3 + i] =
|
||||
I9XX_CSC_COEFF_LIMITED_RANGE;
|
||||
ILK_CSC_COEFF_LIMITED_RANGE;
|
||||
else
|
||||
coeffs[i * 3 + i] = I9XX_CSC_COEFF_1_0;
|
||||
coeffs[i * 3 + i] = ILK_CSC_COEFF_1_0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +232,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
|||
if (INTEL_GEN(dev_priv) > 6) {
|
||||
uint16_t postoff = 0;
|
||||
|
||||
if (intel_crtc_state->limited_color_range)
|
||||
if (limited_color_range)
|
||||
postoff = (16 * (1 << 12) / 255) & 0x1fff;
|
||||
|
||||
I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
|
||||
|
@ -236,7 +243,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
|||
} else {
|
||||
uint32_t mode = CSC_MODE_YUV_TO_RGB;
|
||||
|
||||
if (intel_crtc_state->limited_color_range)
|
||||
if (limited_color_range)
|
||||
mode |= CSC_BLACK_SCREEN_OFFSET;
|
||||
|
||||
I915_WRITE(PIPE_CSC_MODE(pipe), mode);
|
||||
|
@ -651,14 +658,14 @@ void intel_color_init(struct drm_crtc *crtc)
|
|||
dev_priv->display.load_csc_matrix = cherryview_load_csc_matrix;
|
||||
dev_priv->display.load_luts = cherryview_load_luts;
|
||||
} else if (IS_HASWELL(dev_priv)) {
|
||||
dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
|
||||
dev_priv->display.load_csc_matrix = ilk_load_csc_matrix;
|
||||
dev_priv->display.load_luts = haswell_load_luts;
|
||||
} else if (IS_BROADWELL(dev_priv) || IS_GEN9_BC(dev_priv) ||
|
||||
IS_BROXTON(dev_priv)) {
|
||||
dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
|
||||
dev_priv->display.load_csc_matrix = ilk_load_csc_matrix;
|
||||
dev_priv->display.load_luts = broadwell_load_luts;
|
||||
} else if (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) {
|
||||
dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
|
||||
dev_priv->display.load_csc_matrix = ilk_load_csc_matrix;
|
||||
dev_priv->display.load_luts = glk_load_luts;
|
||||
} else {
|
||||
dev_priv->display.load_luts = i9xx_load_luts;
|
||||
|
|
|
@ -956,8 +956,10 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
|
|||
crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev_priv) &&
|
||||
!dmi_check_system(intel_spurious_crt_detect))
|
||||
!dmi_check_system(intel_spurious_crt_detect)) {
|
||||
crt->base.hpd_pin = HPD_CRT;
|
||||
crt->base.hotplug = intel_encoder_hotplug;
|
||||
}
|
||||
|
||||
if (HAS_DDI(dev_priv)) {
|
||||
crt->base.port = PORT_E;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <drm/drm_scdc_helper.h>
|
||||
#include "i915_drv.h"
|
||||
#include "intel_drv.h"
|
||||
|
||||
|
@ -2507,6 +2508,8 @@ static void intel_disable_ddi_dp(struct intel_encoder *encoder,
|
|||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
|
||||
intel_dp->link_trained = false;
|
||||
|
||||
if (old_crtc_state->has_audio)
|
||||
intel_audio_codec_disable(encoder,
|
||||
old_crtc_state, old_conn_state);
|
||||
|
@ -2798,6 +2801,150 @@ intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port)
|
|||
return connector;
|
||||
}
|
||||
|
||||
static int modeset_pipe(struct drm_crtc *crtc,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int ret;
|
||||
|
||||
state = drm_atomic_state_alloc(crtc->dev);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
state->acquire_ctx = ctx;
|
||||
|
||||
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
||||
if (IS_ERR(crtc_state)) {
|
||||
ret = PTR_ERR(crtc_state);
|
||||
goto out;
|
||||
}
|
||||
|
||||
crtc_state->mode_changed = true;
|
||||
|
||||
ret = drm_atomic_add_affected_connectors(state, crtc);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = drm_atomic_add_affected_planes(state, crtc);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = drm_atomic_commit(state);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
drm_atomic_state_put(state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_hdmi_reset_link(struct intel_encoder *encoder,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
struct intel_connector *connector = hdmi->attached_connector;
|
||||
struct i2c_adapter *adapter =
|
||||
intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
|
||||
struct drm_connector_state *conn_state;
|
||||
struct intel_crtc_state *crtc_state;
|
||||
struct intel_crtc *crtc;
|
||||
u8 config;
|
||||
int ret;
|
||||
|
||||
if (!connector || connector->base.status != connector_status_connected)
|
||||
return 0;
|
||||
|
||||
ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
|
||||
ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
conn_state = connector->base.state;
|
||||
|
||||
crtc = to_intel_crtc(conn_state->crtc);
|
||||
if (!crtc)
|
||||
return 0;
|
||||
|
||||
ret = drm_modeset_lock(&crtc->base.mutex, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
crtc_state = to_intel_crtc_state(crtc->base.state);
|
||||
|
||||
WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI));
|
||||
|
||||
if (!crtc_state->base.active)
|
||||
return 0;
|
||||
|
||||
if (!crtc_state->hdmi_high_tmds_clock_ratio &&
|
||||
!crtc_state->hdmi_scrambling)
|
||||
return 0;
|
||||
|
||||
if (conn_state->commit &&
|
||||
!try_wait_for_completion(&conn_state->commit->hw_done))
|
||||
return 0;
|
||||
|
||||
ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to read TMDS config: %d\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) ==
|
||||
crtc_state->hdmi_high_tmds_clock_ratio &&
|
||||
!!(config & SCDC_SCRAMBLING_ENABLE) ==
|
||||
crtc_state->hdmi_scrambling)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* HDMI 2.0 says that one should not send scrambled data
|
||||
* prior to configuring the sink scrambling, and that
|
||||
* TMDS clock/data transmission should be suspended when
|
||||
* changing the TMDS clock rate in the sink. So let's
|
||||
* just do a full modeset here, even though some sinks
|
||||
* would be perfectly happy if were to just reconfigure
|
||||
* the SCDC settings on the fly.
|
||||
*/
|
||||
return modeset_pipe(&crtc->base, ctx);
|
||||
}
|
||||
|
||||
static bool intel_ddi_hotplug(struct intel_encoder *encoder,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
bool changed;
|
||||
int ret;
|
||||
|
||||
changed = intel_encoder_hotplug(encoder, connector);
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
for (;;) {
|
||||
if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA)
|
||||
ret = intel_hdmi_reset_link(encoder, &ctx);
|
||||
else
|
||||
ret = intel_dp_retrain_link(encoder, &ctx);
|
||||
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(&ctx);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static struct intel_connector *
|
||||
intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
|
||||
{
|
||||
|
@ -2842,39 +2989,45 @@ static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dport)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_ddi_max_lanes(struct intel_digital_port *intel_dport)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(intel_dport->base.base.dev);
|
||||
enum port port = intel_dport->base.port;
|
||||
int max_lanes = 4;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 11)
|
||||
return max_lanes;
|
||||
|
||||
if (port == PORT_A || port == PORT_E) {
|
||||
if (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)
|
||||
max_lanes = port == PORT_A ? 4 : 0;
|
||||
else
|
||||
/* Both A and E share 2 lanes */
|
||||
max_lanes = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some BIOS might fail to set this bit on port A if eDP
|
||||
* wasn't lit up at boot. Force this bit set when needed
|
||||
* so we use the proper lane count for our calculations.
|
||||
*/
|
||||
if (intel_ddi_a_force_4_lanes(intel_dport)) {
|
||||
DRM_DEBUG_KMS("Forcing DDI_A_4_LANES for port A\n");
|
||||
intel_dport->saved_port_bits |= DDI_A_4_LANES;
|
||||
max_lanes = 4;
|
||||
}
|
||||
|
||||
return max_lanes;
|
||||
}
|
||||
|
||||
void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port;
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct drm_encoder *encoder;
|
||||
bool init_hdmi, init_dp, init_lspcon = false;
|
||||
int max_lanes;
|
||||
|
||||
if (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES) {
|
||||
switch (port) {
|
||||
case PORT_A:
|
||||
max_lanes = 4;
|
||||
break;
|
||||
case PORT_E:
|
||||
max_lanes = 0;
|
||||
break;
|
||||
default:
|
||||
max_lanes = 4;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (port) {
|
||||
case PORT_A:
|
||||
max_lanes = 2;
|
||||
break;
|
||||
case PORT_E:
|
||||
max_lanes = 2;
|
||||
break;
|
||||
default:
|
||||
max_lanes = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi ||
|
||||
dev_priv->vbt.ddi_port_info[port].supports_hdmi);
|
||||
|
@ -2908,6 +3061,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
|||
drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
|
||||
|
||||
intel_encoder->hotplug = intel_ddi_hotplug;
|
||||
intel_encoder->compute_output_type = intel_ddi_compute_output_type;
|
||||
intel_encoder->compute_config = intel_ddi_compute_config;
|
||||
intel_encoder->enable = intel_enable_ddi;
|
||||
|
@ -2920,10 +3074,17 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
|||
intel_encoder->get_config = intel_ddi_get_config;
|
||||
intel_encoder->suspend = intel_dp_encoder_suspend;
|
||||
intel_encoder->get_power_domains = intel_ddi_get_power_domains;
|
||||
intel_encoder->type = INTEL_OUTPUT_DDI;
|
||||
intel_encoder->power_domain = intel_port_to_power_domain(port);
|
||||
intel_encoder->port = port;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
intel_encoder->cloneable = 0;
|
||||
|
||||
intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
|
||||
(DDI_BUF_PORT_REVERSAL |
|
||||
DDI_A_4_LANES);
|
||||
intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
|
||||
intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port);
|
||||
|
||||
switch (port) {
|
||||
case PORT_A:
|
||||
|
@ -2954,26 +3115,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
|||
MISSING_CASE(port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some BIOS might fail to set this bit on port A if eDP
|
||||
* wasn't lit up at boot. Force this bit set when needed
|
||||
* so we use the proper lane count for our calculations.
|
||||
*/
|
||||
if (intel_ddi_a_force_4_lanes(intel_dig_port)) {
|
||||
DRM_DEBUG_KMS("Forcing DDI_A_4_LANES for port A\n");
|
||||
intel_dig_port->saved_port_bits |= DDI_A_4_LANES;
|
||||
max_lanes = 4;
|
||||
}
|
||||
|
||||
intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
|
||||
intel_dig_port->max_lanes = max_lanes;
|
||||
|
||||
intel_encoder->type = INTEL_OUTPUT_DDI;
|
||||
intel_encoder->power_domain = intel_port_to_power_domain(port);
|
||||
intel_encoder->port = port;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
intel_encoder->cloneable = 0;
|
||||
|
||||
intel_infoframe_init(intel_dig_port);
|
||||
|
||||
if (init_dp) {
|
||||
|
|
|
@ -81,12 +81,16 @@ void intel_device_info_dump_flags(const struct intel_device_info *info,
|
|||
|
||||
static void sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)
|
||||
{
|
||||
int s;
|
||||
|
||||
drm_printf(p, "slice mask: %04x\n", sseu->slice_mask);
|
||||
drm_printf(p, "slice total: %u\n", hweight8(sseu->slice_mask));
|
||||
drm_printf(p, "subslice total: %u\n", sseu_subslice_total(sseu));
|
||||
drm_printf(p, "subslice mask %04x\n", sseu->subslice_mask);
|
||||
drm_printf(p, "subslice per slice: %u\n",
|
||||
hweight8(sseu->subslice_mask));
|
||||
for (s = 0; s < ARRAY_SIZE(sseu->subslice_mask); s++) {
|
||||
drm_printf(p, "slice%d %u subslices mask=%04x\n",
|
||||
s, hweight8(sseu->subslice_mask[s]),
|
||||
sseu->subslice_mask[s]);
|
||||
}
|
||||
drm_printf(p, "EU total: %u\n", sseu->eu_total);
|
||||
drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice);
|
||||
drm_printf(p, "has slice power gating: %s\n",
|
||||
|
@ -120,22 +124,100 @@ void intel_device_info_dump(const struct intel_device_info *info,
|
|||
intel_device_info_dump_flags(info, p);
|
||||
}
|
||||
|
||||
void intel_device_info_dump_topology(const struct sseu_dev_info *sseu,
|
||||
struct drm_printer *p)
|
||||
{
|
||||
int s, ss;
|
||||
|
||||
if (sseu->max_slices == 0) {
|
||||
drm_printf(p, "Unavailable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (s = 0; s < sseu->max_slices; s++) {
|
||||
drm_printf(p, "slice%d: %u subslice(s) (0x%hhx):\n",
|
||||
s, hweight8(sseu->subslice_mask[s]),
|
||||
sseu->subslice_mask[s]);
|
||||
|
||||
for (ss = 0; ss < sseu->max_subslices; ss++) {
|
||||
u16 enabled_eus = sseu_get_eus(sseu, s, ss);
|
||||
|
||||
drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n",
|
||||
ss, hweight16(enabled_eus), enabled_eus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u16 compute_eu_total(const struct sseu_dev_info *sseu)
|
||||
{
|
||||
u16 i, total = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sseu->eu_mask); i++)
|
||||
total += hweight8(sseu->eu_mask[i]);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static void gen10_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
|
||||
const u32 fuse2 = I915_READ(GEN8_FUSE2);
|
||||
int s, ss;
|
||||
const int eu_mask = 0xff;
|
||||
u32 subslice_mask, eu_en;
|
||||
|
||||
sseu->slice_mask = (fuse2 & GEN10_F2_S_ENA_MASK) >>
|
||||
GEN10_F2_S_ENA_SHIFT;
|
||||
sseu->subslice_mask = (1 << 4) - 1;
|
||||
sseu->subslice_mask &= ~((fuse2 & GEN10_F2_SS_DIS_MASK) >>
|
||||
GEN10_F2_SS_DIS_SHIFT);
|
||||
sseu->max_slices = 6;
|
||||
sseu->max_subslices = 4;
|
||||
sseu->max_eus_per_subslice = 8;
|
||||
|
||||
sseu->eu_total = hweight32(~I915_READ(GEN8_EU_DISABLE0));
|
||||
sseu->eu_total += hweight32(~I915_READ(GEN8_EU_DISABLE1));
|
||||
sseu->eu_total += hweight32(~I915_READ(GEN8_EU_DISABLE2));
|
||||
sseu->eu_total += hweight8(~(I915_READ(GEN10_EU_DISABLE3) &
|
||||
GEN10_EU_DIS_SS_MASK));
|
||||
subslice_mask = (1 << 4) - 1;
|
||||
subslice_mask &= ~((fuse2 & GEN10_F2_SS_DIS_MASK) >>
|
||||
GEN10_F2_SS_DIS_SHIFT);
|
||||
|
||||
/*
|
||||
* Slice0 can have up to 3 subslices, but there are only 2 in
|
||||
* slice1/2.
|
||||
*/
|
||||
sseu->subslice_mask[0] = subslice_mask;
|
||||
for (s = 1; s < sseu->max_slices; s++)
|
||||
sseu->subslice_mask[s] = subslice_mask & 0x3;
|
||||
|
||||
/* Slice0 */
|
||||
eu_en = ~I915_READ(GEN8_EU_DISABLE0);
|
||||
for (ss = 0; ss < sseu->max_subslices; ss++)
|
||||
sseu_set_eus(sseu, 0, ss, (eu_en >> (8 * ss)) & eu_mask);
|
||||
/* Slice1 */
|
||||
sseu_set_eus(sseu, 1, 0, (eu_en >> 24) & eu_mask);
|
||||
eu_en = ~I915_READ(GEN8_EU_DISABLE1);
|
||||
sseu_set_eus(sseu, 1, 1, eu_en & eu_mask);
|
||||
/* Slice2 */
|
||||
sseu_set_eus(sseu, 2, 0, (eu_en >> 8) & eu_mask);
|
||||
sseu_set_eus(sseu, 2, 1, (eu_en >> 16) & eu_mask);
|
||||
/* Slice3 */
|
||||
sseu_set_eus(sseu, 3, 0, (eu_en >> 24) & eu_mask);
|
||||
eu_en = ~I915_READ(GEN8_EU_DISABLE2);
|
||||
sseu_set_eus(sseu, 3, 1, eu_en & eu_mask);
|
||||
/* Slice4 */
|
||||
sseu_set_eus(sseu, 4, 0, (eu_en >> 8) & eu_mask);
|
||||
sseu_set_eus(sseu, 4, 1, (eu_en >> 16) & eu_mask);
|
||||
/* Slice5 */
|
||||
sseu_set_eus(sseu, 5, 0, (eu_en >> 24) & eu_mask);
|
||||
eu_en = ~I915_READ(GEN10_EU_DISABLE3);
|
||||
sseu_set_eus(sseu, 5, 1, eu_en & eu_mask);
|
||||
|
||||
/* Do a second pass where we mark the subslices disabled if all their
|
||||
* eus are off.
|
||||
*/
|
||||
for (s = 0; s < sseu->max_slices; s++) {
|
||||
for (ss = 0; ss < sseu->max_subslices; ss++) {
|
||||
if (sseu_get_eus(sseu, s, ss) == 0)
|
||||
sseu->subslice_mask[s] &= ~BIT(ss);
|
||||
}
|
||||
}
|
||||
|
||||
sseu->eu_total = compute_eu_total(sseu);
|
||||
|
||||
/*
|
||||
* CNL is expected to always have a uniform distribution
|
||||
|
@ -156,26 +238,39 @@ static void gen10_sseu_info_init(struct drm_i915_private *dev_priv)
|
|||
static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
|
||||
u32 fuse, eu_dis;
|
||||
u32 fuse;
|
||||
|
||||
fuse = I915_READ(CHV_FUSE_GT);
|
||||
|
||||
sseu->slice_mask = BIT(0);
|
||||
sseu->max_slices = 1;
|
||||
sseu->max_subslices = 2;
|
||||
sseu->max_eus_per_subslice = 8;
|
||||
|
||||
if (!(fuse & CHV_FGT_DISABLE_SS0)) {
|
||||
sseu->subslice_mask |= BIT(0);
|
||||
eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
|
||||
CHV_FGT_EU_DIS_SS0_R1_MASK);
|
||||
sseu->eu_total += 8 - hweight32(eu_dis);
|
||||
u8 disabled_mask =
|
||||
((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >>
|
||||
CHV_FGT_EU_DIS_SS0_R0_SHIFT) |
|
||||
(((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >>
|
||||
CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4);
|
||||
|
||||
sseu->subslice_mask[0] |= BIT(0);
|
||||
sseu_set_eus(sseu, 0, 0, ~disabled_mask);
|
||||
}
|
||||
|
||||
if (!(fuse & CHV_FGT_DISABLE_SS1)) {
|
||||
sseu->subslice_mask |= BIT(1);
|
||||
eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK |
|
||||
CHV_FGT_EU_DIS_SS1_R1_MASK);
|
||||
sseu->eu_total += 8 - hweight32(eu_dis);
|
||||
u8 disabled_mask =
|
||||
((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >>
|
||||
CHV_FGT_EU_DIS_SS1_R0_SHIFT) |
|
||||
(((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >>
|
||||
CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4);
|
||||
|
||||
sseu->subslice_mask[0] |= BIT(1);
|
||||
sseu_set_eus(sseu, 0, 1, ~disabled_mask);
|
||||
}
|
||||
|
||||
sseu->eu_total = compute_eu_total(sseu);
|
||||
|
||||
/*
|
||||
* CHV expected to always have a uniform distribution of EU
|
||||
* across subslices.
|
||||
|
@ -197,41 +292,52 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
|||
{
|
||||
struct intel_device_info *info = mkwrite_device_info(dev_priv);
|
||||
struct sseu_dev_info *sseu = &info->sseu;
|
||||
int s_max = 3, ss_max = 4, eu_max = 8;
|
||||
int s, ss;
|
||||
u32 fuse2, eu_disable;
|
||||
u8 eu_mask = 0xff;
|
||||
u32 fuse2, eu_disable, subslice_mask;
|
||||
const u8 eu_mask = 0xff;
|
||||
|
||||
fuse2 = I915_READ(GEN8_FUSE2);
|
||||
sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
|
||||
|
||||
/* BXT has a single slice and at most 3 subslices. */
|
||||
sseu->max_slices = IS_GEN9_LP(dev_priv) ? 1 : 3;
|
||||
sseu->max_subslices = IS_GEN9_LP(dev_priv) ? 3 : 4;
|
||||
sseu->max_eus_per_subslice = 8;
|
||||
|
||||
/*
|
||||
* The subslice disable field is global, i.e. it applies
|
||||
* to each of the enabled slices.
|
||||
*/
|
||||
sseu->subslice_mask = (1 << ss_max) - 1;
|
||||
sseu->subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
|
||||
GEN9_F2_SS_DIS_SHIFT);
|
||||
subslice_mask = (1 << sseu->max_subslices) - 1;
|
||||
subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
|
||||
GEN9_F2_SS_DIS_SHIFT);
|
||||
|
||||
/*
|
||||
* Iterate through enabled slices and subslices to
|
||||
* count the total enabled EU.
|
||||
*/
|
||||
for (s = 0; s < s_max; s++) {
|
||||
for (s = 0; s < sseu->max_slices; s++) {
|
||||
if (!(sseu->slice_mask & BIT(s)))
|
||||
/* skip disabled slice */
|
||||
continue;
|
||||
|
||||
eu_disable = I915_READ(GEN9_EU_DISABLE(s));
|
||||
for (ss = 0; ss < ss_max; ss++) {
|
||||
int eu_per_ss;
|
||||
sseu->subslice_mask[s] = subslice_mask;
|
||||
|
||||
if (!(sseu->subslice_mask & BIT(ss)))
|
||||
eu_disable = I915_READ(GEN9_EU_DISABLE(s));
|
||||
for (ss = 0; ss < sseu->max_subslices; ss++) {
|
||||
int eu_per_ss;
|
||||
u8 eu_disabled_mask;
|
||||
|
||||
if (!(sseu->subslice_mask[s] & BIT(ss)))
|
||||
/* skip disabled subslice */
|
||||
continue;
|
||||
|
||||
eu_per_ss = eu_max - hweight8((eu_disable >> (ss*8)) &
|
||||
eu_mask);
|
||||
eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask;
|
||||
|
||||
sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
|
||||
|
||||
eu_per_ss = sseu->max_eus_per_subslice -
|
||||
hweight8(eu_disabled_mask);
|
||||
|
||||
/*
|
||||
* Record which subslice(s) has(have) 7 EUs. we
|
||||
|
@ -240,11 +346,11 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
|||
*/
|
||||
if (eu_per_ss == 7)
|
||||
sseu->subslice_7eu[s] |= BIT(ss);
|
||||
|
||||
sseu->eu_total += eu_per_ss;
|
||||
}
|
||||
}
|
||||
|
||||
sseu->eu_total = compute_eu_total(sseu);
|
||||
|
||||
/*
|
||||
* SKL is expected to always have a uniform distribution
|
||||
* of EU across subslices with the exception that any one
|
||||
|
@ -270,8 +376,8 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
|||
sseu->has_eu_pg = sseu->eu_per_subslice > 2;
|
||||
|
||||
if (IS_GEN9_LP(dev_priv)) {
|
||||
#define IS_SS_DISABLED(ss) (!(sseu->subslice_mask & BIT(ss)))
|
||||
info->has_pooled_eu = hweight8(sseu->subslice_mask) == 3;
|
||||
#define IS_SS_DISABLED(ss) (!(sseu->subslice_mask[0] & BIT(ss)))
|
||||
info->has_pooled_eu = hweight8(sseu->subslice_mask[0]) == 3;
|
||||
|
||||
sseu->min_eu_in_pool = 0;
|
||||
if (info->has_pooled_eu) {
|
||||
|
@ -289,19 +395,22 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
|||
static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
|
||||
const int s_max = 3, ss_max = 3, eu_max = 8;
|
||||
int s, ss;
|
||||
u32 fuse2, eu_disable[3]; /* s_max */
|
||||
u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */
|
||||
|
||||
fuse2 = I915_READ(GEN8_FUSE2);
|
||||
sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
|
||||
sseu->max_slices = 3;
|
||||
sseu->max_subslices = 3;
|
||||
sseu->max_eus_per_subslice = 8;
|
||||
|
||||
/*
|
||||
* The subslice disable field is global, i.e. it applies
|
||||
* to each of the enabled slices.
|
||||
*/
|
||||
sseu->subslice_mask = GENMASK(ss_max - 1, 0);
|
||||
sseu->subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
|
||||
GEN8_F2_SS_DIS_SHIFT);
|
||||
subslice_mask = GENMASK(sseu->max_subslices - 1, 0);
|
||||
subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
|
||||
GEN8_F2_SS_DIS_SHIFT);
|
||||
|
||||
eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK;
|
||||
eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) |
|
||||
|
@ -315,30 +424,38 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
|
|||
* Iterate through enabled slices and subslices to
|
||||
* count the total enabled EU.
|
||||
*/
|
||||
for (s = 0; s < s_max; s++) {
|
||||
for (s = 0; s < sseu->max_slices; s++) {
|
||||
if (!(sseu->slice_mask & BIT(s)))
|
||||
/* skip disabled slice */
|
||||
continue;
|
||||
|
||||
for (ss = 0; ss < ss_max; ss++) {
|
||||
sseu->subslice_mask[s] = subslice_mask;
|
||||
|
||||
for (ss = 0; ss < sseu->max_subslices; ss++) {
|
||||
u8 eu_disabled_mask;
|
||||
u32 n_disabled;
|
||||
|
||||
if (!(sseu->subslice_mask & BIT(ss)))
|
||||
if (!(sseu->subslice_mask[ss] & BIT(ss)))
|
||||
/* skip disabled subslice */
|
||||
continue;
|
||||
|
||||
n_disabled = hweight8(eu_disable[s] >> (ss * eu_max));
|
||||
eu_disabled_mask =
|
||||
eu_disable[s] >> (ss * sseu->max_eus_per_subslice);
|
||||
|
||||
sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
|
||||
|
||||
n_disabled = hweight8(eu_disabled_mask);
|
||||
|
||||
/*
|
||||
* Record which subslices have 7 EUs.
|
||||
*/
|
||||
if (eu_max - n_disabled == 7)
|
||||
if (sseu->max_eus_per_subslice - n_disabled == 7)
|
||||
sseu->subslice_7eu[s] |= 1 << ss;
|
||||
|
||||
sseu->eu_total += eu_max - n_disabled;
|
||||
}
|
||||
}
|
||||
|
||||
sseu->eu_total = compute_eu_total(sseu);
|
||||
|
||||
/*
|
||||
* BDW is expected to always have a uniform distribution of EU across
|
||||
* subslices with the exception that any one EU in any one subslice may
|
||||
|
@ -357,6 +474,72 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
|
|||
sseu->has_eu_pg = 0;
|
||||
}
|
||||
|
||||
static void haswell_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_device_info *info = mkwrite_device_info(dev_priv);
|
||||
struct sseu_dev_info *sseu = &info->sseu;
|
||||
u32 fuse1;
|
||||
int s, ss;
|
||||
|
||||
/*
|
||||
* There isn't a register to tell us how many slices/subslices. We
|
||||
* work off the PCI-ids here.
|
||||
*/
|
||||
switch (info->gt) {
|
||||
default:
|
||||
MISSING_CASE(info->gt);
|
||||
/* fall through */
|
||||
case 1:
|
||||
sseu->slice_mask = BIT(0);
|
||||
sseu->subslice_mask[0] = BIT(0);
|
||||
break;
|
||||
case 2:
|
||||
sseu->slice_mask = BIT(0);
|
||||
sseu->subslice_mask[0] = BIT(0) | BIT(1);
|
||||
break;
|
||||
case 3:
|
||||
sseu->slice_mask = BIT(0) | BIT(1);
|
||||
sseu->subslice_mask[0] = BIT(0) | BIT(1);
|
||||
sseu->subslice_mask[1] = BIT(0) | BIT(1);
|
||||
break;
|
||||
}
|
||||
|
||||
sseu->max_slices = hweight8(sseu->slice_mask);
|
||||
sseu->max_subslices = hweight8(sseu->subslice_mask[0]);
|
||||
|
||||
fuse1 = I915_READ(HSW_PAVP_FUSE1);
|
||||
switch ((fuse1 & HSW_F1_EU_DIS_MASK) >> HSW_F1_EU_DIS_SHIFT) {
|
||||
default:
|
||||
MISSING_CASE((fuse1 & HSW_F1_EU_DIS_MASK) >>
|
||||
HSW_F1_EU_DIS_SHIFT);
|
||||
/* fall through */
|
||||
case HSW_F1_EU_DIS_10EUS:
|
||||
sseu->eu_per_subslice = 10;
|
||||
break;
|
||||
case HSW_F1_EU_DIS_8EUS:
|
||||
sseu->eu_per_subslice = 8;
|
||||
break;
|
||||
case HSW_F1_EU_DIS_6EUS:
|
||||
sseu->eu_per_subslice = 6;
|
||||
break;
|
||||
}
|
||||
sseu->max_eus_per_subslice = sseu->eu_per_subslice;
|
||||
|
||||
for (s = 0; s < sseu->max_slices; s++) {
|
||||
for (ss = 0; ss < sseu->max_subslices; ss++) {
|
||||
sseu_set_eus(sseu, s, ss,
|
||||
(1UL << sseu->eu_per_subslice) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
sseu->eu_total = compute_eu_total(sseu);
|
||||
|
||||
/* No powergating for you. */
|
||||
sseu->has_slice_pg = 0;
|
||||
sseu->has_subslice_pg = 0;
|
||||
sseu->has_eu_pg = 0;
|
||||
}
|
||||
|
||||
static u32 read_reference_ts_freq(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
u32 ts_override = I915_READ(GEN9_TIMESTAMP_OVERRIDE);
|
||||
|
@ -489,6 +672,9 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
|
|||
info->num_scalers[PIPE_C] = 1;
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(I915_NUM_ENGINES >
|
||||
sizeof(intel_ring_mask_t) * BITS_PER_BYTE);
|
||||
|
||||
/*
|
||||
* Skylake and Broxton currently don't expose the topmost plane as its
|
||||
* use is exclusive with the legacy cursor and we only want to expose
|
||||
|
@ -574,7 +760,9 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
|
|||
}
|
||||
|
||||
/* Initialize slice/subslice/EU info */
|
||||
if (IS_CHERRYVIEW(dev_priv))
|
||||
if (IS_HASWELL(dev_priv))
|
||||
haswell_sseu_info_init(dev_priv);
|
||||
else if (IS_CHERRYVIEW(dev_priv))
|
||||
cherryview_sseu_info_init(dev_priv);
|
||||
else if (IS_BROADWELL(dev_priv))
|
||||
broadwell_sseu_info_init(dev_priv);
|
||||
|
|
|
@ -96,6 +96,7 @@ enum intel_platform {
|
|||
func(has_l3_dpf); \
|
||||
func(has_llc); \
|
||||
func(has_logical_ring_contexts); \
|
||||
func(has_logical_ring_elsq); \
|
||||
func(has_logical_ring_preemption); \
|
||||
func(has_overlay); \
|
||||
func(has_pooled_eu); \
|
||||
|
@ -112,10 +113,13 @@ enum intel_platform {
|
|||
func(supports_tv); \
|
||||
func(has_ipc);
|
||||
|
||||
#define GEN_MAX_SLICES (6) /* CNL upper bound */
|
||||
#define GEN_MAX_SUBSLICES (7)
|
||||
|
||||
struct sseu_dev_info {
|
||||
u8 slice_mask;
|
||||
u8 subslice_mask;
|
||||
u8 eu_total;
|
||||
u8 subslice_mask[GEN_MAX_SUBSLICES];
|
||||
u16 eu_total;
|
||||
u8 eu_per_subslice;
|
||||
u8 min_eu_in_pool;
|
||||
/* For each slice, which subslice(s) has(have) 7 EUs (bitfield)? */
|
||||
|
@ -123,8 +127,21 @@ struct sseu_dev_info {
|
|||
u8 has_slice_pg:1;
|
||||
u8 has_subslice_pg:1;
|
||||
u8 has_eu_pg:1;
|
||||
|
||||
/* Topology fields */
|
||||
u8 max_slices;
|
||||
u8 max_subslices;
|
||||
u8 max_eus_per_subslice;
|
||||
|
||||
/* We don't have more than 8 eus per subslice at the moment and as we
|
||||
* store eus enabled using bits, no need to multiply by eus per
|
||||
* subslice.
|
||||
*/
|
||||
u8 eu_mask[GEN_MAX_SLICES * GEN_MAX_SUBSLICES];
|
||||
};
|
||||
|
||||
typedef u8 intel_ring_mask_t;
|
||||
|
||||
struct intel_device_info {
|
||||
u16 device_id;
|
||||
u16 gen_mask;
|
||||
|
@ -132,19 +149,19 @@ struct intel_device_info {
|
|||
u8 gen;
|
||||
u8 gt; /* GT number, 0 if undefined */
|
||||
u8 num_rings;
|
||||
u8 ring_mask; /* Rings supported by the HW */
|
||||
intel_ring_mask_t ring_mask; /* Rings supported by the HW */
|
||||
|
||||
enum intel_platform platform;
|
||||
u32 platform_mask;
|
||||
|
||||
unsigned int page_sizes; /* page sizes supported by the HW */
|
||||
|
||||
u32 display_mmio_offset;
|
||||
|
||||
u8 num_pipes;
|
||||
u8 num_sprites[I915_MAX_PIPES];
|
||||
u8 num_scalers[I915_MAX_PIPES];
|
||||
|
||||
unsigned int page_sizes; /* page sizes supported by the HW */
|
||||
|
||||
#define DEFINE_FLAG(name) u8 name:1
|
||||
DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG);
|
||||
#undef DEFINE_FLAG
|
||||
|
@ -173,7 +190,49 @@ struct intel_driver_caps {
|
|||
|
||||
static inline unsigned int sseu_subslice_total(const struct sseu_dev_info *sseu)
|
||||
{
|
||||
return hweight8(sseu->slice_mask) * hweight8(sseu->subslice_mask);
|
||||
unsigned int i, total = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sseu->subslice_mask); i++)
|
||||
total += hweight8(sseu->subslice_mask[i]);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static inline int sseu_eu_idx(const struct sseu_dev_info *sseu,
|
||||
int slice, int subslice)
|
||||
{
|
||||
int subslice_stride = DIV_ROUND_UP(sseu->max_eus_per_subslice,
|
||||
BITS_PER_BYTE);
|
||||
int slice_stride = sseu->max_subslices * subslice_stride;
|
||||
|
||||
return slice * slice_stride + subslice * subslice_stride;
|
||||
}
|
||||
|
||||
static inline u16 sseu_get_eus(const struct sseu_dev_info *sseu,
|
||||
int slice, int subslice)
|
||||
{
|
||||
int i, offset = sseu_eu_idx(sseu, slice, subslice);
|
||||
u16 eu_mask = 0;
|
||||
|
||||
for (i = 0;
|
||||
i < DIV_ROUND_UP(sseu->max_eus_per_subslice, BITS_PER_BYTE); i++) {
|
||||
eu_mask |= ((u16) sseu->eu_mask[offset + i]) <<
|
||||
(i * BITS_PER_BYTE);
|
||||
}
|
||||
|
||||
return eu_mask;
|
||||
}
|
||||
|
||||
static inline void sseu_set_eus(struct sseu_dev_info *sseu,
|
||||
int slice, int subslice, u16 eu_mask)
|
||||
{
|
||||
int i, offset = sseu_eu_idx(sseu, slice, subslice);
|
||||
|
||||
for (i = 0;
|
||||
i < DIV_ROUND_UP(sseu->max_eus_per_subslice, BITS_PER_BYTE); i++) {
|
||||
sseu->eu_mask[offset + i] =
|
||||
(eu_mask >> (BITS_PER_BYTE * i)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
const char *intel_platform_name(enum intel_platform platform);
|
||||
|
@ -185,6 +244,8 @@ void intel_device_info_dump_flags(const struct intel_device_info *info,
|
|||
struct drm_printer *p);
|
||||
void intel_device_info_dump_runtime(const struct intel_device_info *info,
|
||||
struct drm_printer *p);
|
||||
void intel_device_info_dump_topology(const struct sseu_dev_info *sseu,
|
||||
struct drm_printer *p);
|
||||
|
||||
void intel_driver_caps_print(const struct intel_driver_caps *caps,
|
||||
struct drm_printer *p);
|
||||
|
|
|
@ -2067,9 +2067,18 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
|
|||
}
|
||||
}
|
||||
|
||||
static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state)
|
||||
{
|
||||
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
|
||||
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
||||
|
||||
return INTEL_GEN(dev_priv) < 4 || plane->has_fbc;
|
||||
}
|
||||
|
||||
struct i915_vma *
|
||||
intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
|
||||
unsigned int rotation,
|
||||
bool uses_fence,
|
||||
unsigned long *out_flags)
|
||||
{
|
||||
struct drm_device *dev = fb->dev;
|
||||
|
@ -2122,7 +2131,9 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
|
|||
if (IS_ERR(vma))
|
||||
goto err;
|
||||
|
||||
if (i915_vma_is_map_and_fenceable(vma)) {
|
||||
if (uses_fence && i915_vma_is_map_and_fenceable(vma)) {
|
||||
int ret;
|
||||
|
||||
/* Install a fence for tiled scan-out. Pre-i965 always needs a
|
||||
* fence, whereas 965+ only requires a fence if using
|
||||
* framebuffer compression. For simplicity, we always, when
|
||||
|
@ -2139,7 +2150,14 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
|
|||
* something and try to run the system in a "less than optimal"
|
||||
* mode that matches the user configuration.
|
||||
*/
|
||||
if (i915_vma_pin_fence(vma) == 0 && vma->fence)
|
||||
ret = i915_vma_pin_fence(vma);
|
||||
if (ret != 0 && INTEL_GEN(dev_priv) < 4) {
|
||||
i915_gem_object_unpin_from_display_plane(vma);
|
||||
vma = ERR_PTR(ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ret == 0 && vma->fence)
|
||||
*out_flags |= PLANE_HAS_FENCE;
|
||||
}
|
||||
|
||||
|
@ -2828,6 +2846,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
|
|||
intel_state->vma =
|
||||
intel_pin_and_fence_fb_obj(fb,
|
||||
primary->state->rotation,
|
||||
intel_plane_uses_fence(intel_state),
|
||||
&intel_state->flags);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (IS_ERR(intel_state->vma)) {
|
||||
|
@ -12034,6 +12053,14 @@ static int intel_atomic_check(struct drm_device *dev,
|
|||
int ret, i;
|
||||
bool any_ms = false;
|
||||
|
||||
/* Catch I915_MODE_FLAG_INHERITED */
|
||||
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
|
||||
crtc_state, i) {
|
||||
if (crtc_state->mode.private_flags !=
|
||||
old_crtc_state->mode.private_flags)
|
||||
crtc_state->mode_changed = true;
|
||||
}
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -12042,10 +12069,6 @@ static int intel_atomic_check(struct drm_device *dev,
|
|||
struct intel_crtc_state *pipe_config =
|
||||
to_intel_crtc_state(crtc_state);
|
||||
|
||||
/* Catch I915_MODE_FLAG_INHERITED */
|
||||
if (crtc_state->mode.private_flags != old_crtc_state->mode.private_flags)
|
||||
crtc_state->mode_changed = true;
|
||||
|
||||
if (!needs_modeset(crtc_state))
|
||||
continue;
|
||||
|
||||
|
@ -12054,13 +12077,6 @@ static int intel_atomic_check(struct drm_device *dev,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* FIXME: For only active_changed we shouldn't need to do any
|
||||
* state recomputation at all. */
|
||||
|
||||
ret = drm_atomic_add_affected_connectors(state, crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_modeset_pipe_config(crtc, pipe_config);
|
||||
if (ret) {
|
||||
intel_dump_pipe_config(to_intel_crtc(crtc),
|
||||
|
@ -12079,10 +12095,6 @@ static int intel_atomic_check(struct drm_device *dev,
|
|||
if (needs_modeset(crtc_state))
|
||||
any_ms = true;
|
||||
|
||||
ret = drm_atomic_add_affected_planes(state, crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
|
||||
needs_modeset(crtc_state) ?
|
||||
"[modeset]" : "[fastset]");
|
||||
|
@ -12600,23 +12612,23 @@ struct wait_rps_boost {
|
|||
struct wait_queue_entry wait;
|
||||
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
};
|
||||
|
||||
static int do_rps_boost(struct wait_queue_entry *_wait,
|
||||
unsigned mode, int sync, void *key)
|
||||
{
|
||||
struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait);
|
||||
struct drm_i915_gem_request *rq = wait->request;
|
||||
struct i915_request *rq = wait->request;
|
||||
|
||||
/*
|
||||
* If we missed the vblank, but the request is already running it
|
||||
* is reasonable to assume that it will complete before the next
|
||||
* vblank without our intervention, so leave RPS alone.
|
||||
*/
|
||||
if (!i915_gem_request_started(rq))
|
||||
if (!i915_request_started(rq))
|
||||
gen6_rps_boost(rq, NULL);
|
||||
i915_gem_request_put(rq);
|
||||
i915_request_put(rq);
|
||||
|
||||
drm_crtc_vblank_put(wait->crtc);
|
||||
|
||||
|
@ -12654,6 +12666,42 @@ static void add_rps_boost_after_vblank(struct drm_crtc *crtc,
|
|||
add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait);
|
||||
}
|
||||
|
||||
static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
|
||||
{
|
||||
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
|
||||
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
||||
struct drm_framebuffer *fb = plane_state->base.fb;
|
||||
struct i915_vma *vma;
|
||||
|
||||
if (plane->id == PLANE_CURSOR &&
|
||||
INTEL_INFO(dev_priv)->cursor_needs_physical) {
|
||||
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
||||
const int align = intel_cursor_alignment(dev_priv);
|
||||
|
||||
return i915_gem_object_attach_phys(obj, align);
|
||||
}
|
||||
|
||||
vma = intel_pin_and_fence_fb_obj(fb,
|
||||
plane_state->base.rotation,
|
||||
intel_plane_uses_fence(plane_state),
|
||||
&plane_state->flags);
|
||||
if (IS_ERR(vma))
|
||||
return PTR_ERR(vma);
|
||||
|
||||
plane_state->vma = vma;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
|
||||
{
|
||||
struct i915_vma *vma;
|
||||
|
||||
vma = fetch_and_zero(&old_plane_state->vma);
|
||||
if (vma)
|
||||
intel_unpin_fb_vma(vma, old_plane_state->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_prepare_plane_fb - Prepare fb for usage on plane
|
||||
* @plane: drm plane to prepare for
|
||||
|
@ -12728,22 +12776,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (plane->type == DRM_PLANE_TYPE_CURSOR &&
|
||||
INTEL_INFO(dev_priv)->cursor_needs_physical) {
|
||||
const int align = intel_cursor_alignment(dev_priv);
|
||||
|
||||
ret = i915_gem_object_attach_phys(obj, align);
|
||||
} else {
|
||||
struct i915_vma *vma;
|
||||
|
||||
vma = intel_pin_and_fence_fb_obj(fb,
|
||||
new_state->rotation,
|
||||
&to_intel_plane_state(new_state)->flags);
|
||||
if (!IS_ERR(vma))
|
||||
to_intel_plane_state(new_state)->vma = vma;
|
||||
else
|
||||
ret = PTR_ERR(vma);
|
||||
}
|
||||
ret = intel_plane_pin_fb(to_intel_plane_state(new_state));
|
||||
|
||||
i915_gem_object_wait_priority(obj, 0, I915_PRIORITY_DISPLAY);
|
||||
|
||||
|
@ -12787,15 +12820,12 @@ void
|
|||
intel_cleanup_plane_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct i915_vma *vma;
|
||||
struct drm_i915_private *dev_priv = to_i915(plane->dev);
|
||||
|
||||
/* Should only be called after a successful intel_prepare_plane_fb()! */
|
||||
vma = fetch_and_zero(&to_intel_plane_state(old_state)->vma);
|
||||
if (vma) {
|
||||
mutex_lock(&plane->dev->struct_mutex);
|
||||
intel_unpin_fb_vma(vma, to_intel_plane_state(old_state)->flags);
|
||||
mutex_unlock(&plane->dev->struct_mutex);
|
||||
}
|
||||
mutex_lock(&dev_priv->drm.struct_mutex);
|
||||
intel_plane_unpin_fb(to_intel_plane_state(old_state));
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -13080,7 +13110,6 @@ intel_legacy_cursor_update(struct drm_plane *plane,
|
|||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
struct drm_framebuffer *old_fb;
|
||||
struct drm_crtc_state *crtc_state = crtc->state;
|
||||
struct i915_vma *old_vma, *vma;
|
||||
|
||||
/*
|
||||
* When crtc is inactive or there is a modeset pending,
|
||||
|
@ -13139,27 +13168,9 @@ intel_legacy_cursor_update(struct drm_plane *plane,
|
|||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
if (INTEL_INFO(dev_priv)->cursor_needs_physical) {
|
||||
int align = intel_cursor_alignment(dev_priv);
|
||||
|
||||
ret = i915_gem_object_attach_phys(intel_fb_obj(fb), align);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("failed to attach phys object\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
} else {
|
||||
vma = intel_pin_and_fence_fb_obj(fb,
|
||||
new_plane_state->rotation,
|
||||
&to_intel_plane_state(new_plane_state)->flags);
|
||||
if (IS_ERR(vma)) {
|
||||
DRM_DEBUG_KMS("failed to pin object\n");
|
||||
|
||||
ret = PTR_ERR(vma);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
to_intel_plane_state(new_plane_state)->vma = vma;
|
||||
}
|
||||
ret = intel_plane_pin_fb(to_intel_plane_state(new_plane_state));
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
old_fb = old_plane_state->fb;
|
||||
|
||||
|
@ -13179,10 +13190,7 @@ intel_legacy_cursor_update(struct drm_plane *plane,
|
|||
intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc));
|
||||
}
|
||||
|
||||
old_vma = fetch_and_zero(&to_intel_plane_state(old_plane_state)->vma);
|
||||
if (old_vma)
|
||||
intel_unpin_fb_vma(old_vma,
|
||||
to_intel_plane_state(old_plane_state)->flags);
|
||||
intel_plane_unpin_fb(to_intel_plane_state(old_plane_state));
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
|
@ -13210,6 +13218,32 @@ static const struct drm_plane_funcs intel_cursor_plane_funcs = {
|
|||
.format_mod_supported = intel_cursor_plane_format_mod_supported,
|
||||
};
|
||||
|
||||
static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
|
||||
enum i9xx_plane_id i9xx_plane)
|
||||
{
|
||||
if (!HAS_FBC(dev_priv))
|
||||
return false;
|
||||
|
||||
if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
|
||||
return i9xx_plane == PLANE_A; /* tied to pipe A */
|
||||
else if (IS_IVYBRIDGE(dev_priv))
|
||||
return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||
|
||||
i9xx_plane == PLANE_C;
|
||||
else if (INTEL_GEN(dev_priv) >= 4)
|
||||
return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;
|
||||
else
|
||||
return i9xx_plane == PLANE_A;
|
||||
}
|
||||
|
||||
static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe, enum plane_id plane_id)
|
||||
{
|
||||
if (!HAS_FBC(dev_priv))
|
||||
return false;
|
||||
|
||||
return pipe == PIPE_A && plane_id == PLANE_PRIMARY;
|
||||
}
|
||||
|
||||
static struct intel_plane *
|
||||
intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
|
||||
{
|
||||
|
@ -13252,6 +13286,21 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|||
primary->i9xx_plane = (enum i9xx_plane_id) pipe;
|
||||
primary->id = PLANE_PRIMARY;
|
||||
primary->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, primary->id);
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 9)
|
||||
primary->has_fbc = skl_plane_has_fbc(dev_priv,
|
||||
primary->pipe,
|
||||
primary->id);
|
||||
else
|
||||
primary->has_fbc = i9xx_plane_has_fbc(dev_priv,
|
||||
primary->i9xx_plane);
|
||||
|
||||
if (primary->has_fbc) {
|
||||
struct intel_fbc *fbc = &dev_priv->fbc;
|
||||
|
||||
fbc->possible_framebuffer_bits |= primary->frontbuffer_bit;
|
||||
}
|
||||
|
||||
primary->check_plane = intel_check_primary_plane;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 9) {
|
||||
|
|
|
@ -139,6 +139,17 @@ enum dpio_phy {
|
|||
|
||||
#define I915_NUM_PHYS_VLV 2
|
||||
|
||||
enum aux_ch {
|
||||
AUX_CH_A,
|
||||
AUX_CH_B,
|
||||
AUX_CH_C,
|
||||
AUX_CH_D,
|
||||
_AUX_CH_E, /* does not exist */
|
||||
AUX_CH_F,
|
||||
};
|
||||
|
||||
#define aux_ch_name(a) ((a) + 'A')
|
||||
|
||||
enum intel_display_power_domain {
|
||||
POWER_DOMAIN_PIPE_A,
|
||||
POWER_DOMAIN_PIPE_B,
|
||||
|
@ -175,6 +186,7 @@ enum intel_display_power_domain {
|
|||
POWER_DOMAIN_AUX_C,
|
||||
POWER_DOMAIN_AUX_D,
|
||||
POWER_DOMAIN_AUX_F,
|
||||
POWER_DOMAIN_AUX_IO_A,
|
||||
POWER_DOMAIN_GMBUS,
|
||||
POWER_DOMAIN_MODESET,
|
||||
POWER_DOMAIN_GT_IRQ,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -248,6 +248,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
|
|||
int tries;
|
||||
u32 training_pattern;
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
bool channel_eq = false;
|
||||
|
||||
training_pattern = intel_dp_training_pattern(intel_dp);
|
||||
|
||||
|
@ -259,7 +260,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
|
|||
return false;
|
||||
}
|
||||
|
||||
intel_dp->channel_eq_status = false;
|
||||
for (tries = 0; tries < 5; tries++) {
|
||||
|
||||
drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
|
||||
|
@ -279,7 +279,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
|
|||
|
||||
if (drm_dp_channel_eq_ok(link_status,
|
||||
intel_dp->lane_count)) {
|
||||
intel_dp->channel_eq_status = true;
|
||||
channel_eq = true;
|
||||
DRM_DEBUG_KMS("Channel EQ done. DP Training "
|
||||
"successful\n");
|
||||
break;
|
||||
|
@ -301,12 +301,14 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
|
|||
|
||||
intel_dp_set_idle_link_train(intel_dp);
|
||||
|
||||
return intel_dp->channel_eq_status;
|
||||
return channel_eq;
|
||||
|
||||
}
|
||||
|
||||
void intel_dp_stop_link_train(struct intel_dp *intel_dp)
|
||||
{
|
||||
intel_dp->link_trained = true;
|
||||
|
||||
intel_dp_set_link_train(intel_dp,
|
||||
DP_TRAINING_PATTERN_DISABLE);
|
||||
}
|
||||
|
|
|
@ -215,7 +215,8 @@ struct intel_encoder {
|
|||
enum intel_output_type type;
|
||||
enum port port;
|
||||
unsigned int cloneable;
|
||||
void (*hot_plug)(struct intel_encoder *);
|
||||
bool (*hotplug)(struct intel_encoder *encoder,
|
||||
struct intel_connector *connector);
|
||||
enum intel_output_type (*compute_output_type)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
|
@ -935,6 +936,7 @@ struct intel_plane {
|
|||
enum plane_id id;
|
||||
enum pipe pipe;
|
||||
bool can_scale;
|
||||
bool has_fbc;
|
||||
int max_downscale;
|
||||
uint32_t frontbuffer_bit;
|
||||
|
||||
|
@ -1041,17 +1043,16 @@ struct intel_dp_compliance {
|
|||
|
||||
struct intel_dp {
|
||||
i915_reg_t output_reg;
|
||||
i915_reg_t aux_ch_ctl_reg;
|
||||
i915_reg_t aux_ch_data_reg[5];
|
||||
uint32_t DP;
|
||||
int link_rate;
|
||||
uint8_t lane_count;
|
||||
uint8_t sink_count;
|
||||
bool link_mst;
|
||||
bool link_trained;
|
||||
bool has_audio;
|
||||
bool detect_done;
|
||||
bool channel_eq_status;
|
||||
bool reset_link_params;
|
||||
enum aux_ch aux_ch;
|
||||
uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
|
||||
uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
|
||||
|
@ -1126,6 +1127,9 @@ struct intel_dp {
|
|||
int send_bytes,
|
||||
uint32_t aux_clock_divider);
|
||||
|
||||
i915_reg_t (*aux_ch_ctl_reg)(struct intel_dp *dp);
|
||||
i915_reg_t (*aux_ch_data_reg)(struct intel_dp *dp, int index);
|
||||
|
||||
/* This is called before a link training is starterd */
|
||||
void (*prepare_link_retrain)(struct intel_dp *intel_dp);
|
||||
|
||||
|
@ -1508,6 +1512,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
|
|||
struct i915_vma *
|
||||
intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
|
||||
unsigned int rotation,
|
||||
bool uses_fence,
|
||||
unsigned long *out_flags);
|
||||
void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags);
|
||||
struct drm_framebuffer *
|
||||
|
@ -1622,6 +1627,8 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
|
|||
int link_rate, uint8_t lane_count);
|
||||
void intel_dp_start_link_train(struct intel_dp *intel_dp);
|
||||
void intel_dp_stop_link_train(struct intel_dp *intel_dp);
|
||||
int intel_dp_retrain_link(struct intel_encoder *encoder,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
|
||||
void intel_dp_encoder_reset(struct drm_encoder *encoder);
|
||||
void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
|
||||
|
@ -1701,7 +1708,8 @@ int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
|
|||
void intel_dvo_init(struct drm_i915_private *dev_priv);
|
||||
/* intel_hotplug.c */
|
||||
void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
|
||||
|
||||
bool intel_encoder_hotplug(struct intel_encoder *encoder,
|
||||
struct intel_connector *connector);
|
||||
|
||||
/* legacy fbdev emulation in intel_fbdev.c */
|
||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
||||
|
@ -1863,6 +1871,7 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
|
|||
|
||||
/* intel_psr.c */
|
||||
#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
|
||||
void intel_psr_init_dpcd(struct intel_dp *intel_dp);
|
||||
void intel_psr_enable(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_psr_disable(struct intel_dp *intel_dp,
|
||||
|
@ -1989,8 +1998,7 @@ void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv);
|
|||
void gen6_rps_busy(struct drm_i915_private *dev_priv);
|
||||
void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
|
||||
void gen6_rps_idle(struct drm_i915_private *dev_priv);
|
||||
void gen6_rps_boost(struct drm_i915_gem_request *rq,
|
||||
struct intel_rps_client *rps);
|
||||
void gen6_rps_boost(struct i915_request *rq, struct intel_rps_client *rps);
|
||||
void g4x_wm_get_hw_state(struct drm_device *dev);
|
||||
void vlv_wm_get_hw_state(struct drm_device *dev);
|
||||
void ilk_wm_get_hw_state(struct drm_device *dev);
|
||||
|
|
|
@ -123,6 +123,22 @@ static const struct engine_info intel_engines[] = {
|
|||
.mmio_base = GEN8_BSD2_RING_BASE,
|
||||
.irq_shift = GEN8_VCS2_IRQ_SHIFT,
|
||||
},
|
||||
[VCS3] = {
|
||||
.hw_id = VCS3_HW,
|
||||
.uabi_id = I915_EXEC_BSD,
|
||||
.class = VIDEO_DECODE_CLASS,
|
||||
.instance = 2,
|
||||
.mmio_base = GEN11_BSD3_RING_BASE,
|
||||
.irq_shift = 0, /* not used */
|
||||
},
|
||||
[VCS4] = {
|
||||
.hw_id = VCS4_HW,
|
||||
.uabi_id = I915_EXEC_BSD,
|
||||
.class = VIDEO_DECODE_CLASS,
|
||||
.instance = 3,
|
||||
.mmio_base = GEN11_BSD4_RING_BASE,
|
||||
.irq_shift = 0, /* not used */
|
||||
},
|
||||
[VECS] = {
|
||||
.hw_id = VECS_HW,
|
||||
.uabi_id = I915_EXEC_VEBOX,
|
||||
|
@ -131,6 +147,14 @@ static const struct engine_info intel_engines[] = {
|
|||
.mmio_base = VEBOX_RING_BASE,
|
||||
.irq_shift = GEN8_VECS_IRQ_SHIFT,
|
||||
},
|
||||
[VECS2] = {
|
||||
.hw_id = VECS2_HW,
|
||||
.uabi_id = I915_EXEC_VEBOX,
|
||||
.class = VIDEO_ENHANCEMENT_CLASS,
|
||||
.instance = 1,
|
||||
.mmio_base = GEN11_VEBOX2_RING_BASE,
|
||||
.irq_shift = 0, /* not used */
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -210,6 +234,9 @@ intel_engine_setup(struct drm_i915_private *dev_priv,
|
|||
GEM_BUG_ON(info->class >= ARRAY_SIZE(intel_engine_classes));
|
||||
class_info = &intel_engine_classes[info->class];
|
||||
|
||||
BUILD_BUG_ON(MAX_ENGINE_CLASS >= BIT(GEN11_ENGINE_CLASS_WIDTH));
|
||||
BUILD_BUG_ON(MAX_ENGINE_INSTANCE >= BIT(GEN11_ENGINE_INSTANCE_WIDTH));
|
||||
|
||||
if (GEM_WARN_ON(info->class > MAX_ENGINE_CLASS))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -230,7 +257,25 @@ intel_engine_setup(struct drm_i915_private *dev_priv,
|
|||
class_info->name, info->instance) >=
|
||||
sizeof(engine->name));
|
||||
engine->hw_id = engine->guc_id = info->hw_id;
|
||||
engine->mmio_base = info->mmio_base;
|
||||
if (INTEL_GEN(dev_priv) >= 11) {
|
||||
switch (engine->id) {
|
||||
case VCS:
|
||||
engine->mmio_base = GEN11_BSD_RING_BASE;
|
||||
break;
|
||||
case VCS2:
|
||||
engine->mmio_base = GEN11_BSD2_RING_BASE;
|
||||
break;
|
||||
case VECS:
|
||||
engine->mmio_base = GEN11_VEBOX_RING_BASE;
|
||||
break;
|
||||
default:
|
||||
/* take the original value for all other engines */
|
||||
engine->mmio_base = info->mmio_base;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
engine->mmio_base = info->mmio_base;
|
||||
}
|
||||
engine->irq_shift = info->irq_shift;
|
||||
engine->class = info->class;
|
||||
engine->instance = info->instance;
|
||||
|
@ -423,6 +468,7 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine)
|
|||
BUILD_BUG_ON_NOT_POWER_OF_2(execlists_num_ports(execlists));
|
||||
GEM_BUG_ON(execlists_num_ports(execlists) > EXECLIST_MAX_PORTS);
|
||||
|
||||
execlists->queue_priority = INT_MIN;
|
||||
execlists->queue = RB_ROOT;
|
||||
execlists->first = NULL;
|
||||
}
|
||||
|
@ -1426,20 +1472,20 @@ int init_workarounds_ring(struct intel_engine_cs *engine)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
|
||||
int intel_ring_workarounds_emit(struct i915_request *rq)
|
||||
{
|
||||
struct i915_workarounds *w = &req->i915->workarounds;
|
||||
struct i915_workarounds *w = &rq->i915->workarounds;
|
||||
u32 *cs;
|
||||
int ret, i;
|
||||
|
||||
if (w->count == 0)
|
||||
return 0;
|
||||
|
||||
ret = req->engine->emit_flush(req, EMIT_BARRIER);
|
||||
ret = rq->engine->emit_flush(rq, EMIT_BARRIER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cs = intel_ring_begin(req, (w->count * 2 + 2));
|
||||
cs = intel_ring_begin(rq, w->count * 2 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1450,9 +1496,9 @@ int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
|
|||
}
|
||||
*cs++ = MI_NOOP;
|
||||
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
ret = req->engine->emit_flush(req, EMIT_BARRIER);
|
||||
ret = rq->engine->emit_flush(rq, EMIT_BARRIER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1552,7 +1598,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine)
|
|||
{
|
||||
const struct i915_gem_context * const kernel_context =
|
||||
engine->i915->kernel_context;
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
|
||||
lockdep_assert_held(&engine->i915->drm.struct_mutex);
|
||||
|
||||
|
@ -1664,13 +1710,13 @@ unsigned int intel_engines_has_context_isolation(struct drm_i915_private *i915)
|
|||
}
|
||||
|
||||
static void print_request(struct drm_printer *m,
|
||||
struct drm_i915_gem_request *rq,
|
||||
struct i915_request *rq,
|
||||
const char *prefix)
|
||||
{
|
||||
drm_printf(m, "%s%x%s [%x:%x] prio=%d @ %dms: %s\n", prefix,
|
||||
drm_printf(m, "%s%x%s [%llx:%x] prio=%d @ %dms: %s\n", prefix,
|
||||
rq->global_seqno,
|
||||
i915_gem_request_completed(rq) ? "!" : "",
|
||||
rq->ctx->hw_id, rq->fence.seqno,
|
||||
i915_request_completed(rq) ? "!" : "",
|
||||
rq->fence.context, rq->fence.seqno,
|
||||
rq->priotree.priority,
|
||||
jiffies_to_msecs(jiffies - rq->emitted_jiffies),
|
||||
rq->timeline->common->name);
|
||||
|
@ -1803,7 +1849,7 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine,
|
|||
|
||||
rcu_read_lock();
|
||||
for (idx = 0; idx < execlists_num_ports(execlists); idx++) {
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
unsigned int count;
|
||||
|
||||
rq = port_unpack(&execlists->port[idx], &count);
|
||||
|
@ -1837,7 +1883,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
|
|||
struct intel_breadcrumbs * const b = &engine->breadcrumbs;
|
||||
const struct intel_engine_execlists * const execlists = &engine->execlists;
|
||||
struct i915_gpu_error * const error = &engine->i915->gpu_error;
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct rb_node *rb;
|
||||
|
||||
if (header) {
|
||||
|
@ -1866,12 +1912,12 @@ void intel_engine_dump(struct intel_engine_cs *engine,
|
|||
drm_printf(m, "\tRequests:\n");
|
||||
|
||||
rq = list_first_entry(&engine->timeline->requests,
|
||||
struct drm_i915_gem_request, link);
|
||||
struct i915_request, link);
|
||||
if (&rq->link != &engine->timeline->requests)
|
||||
print_request(m, rq, "\t\tfirst ");
|
||||
|
||||
rq = list_last_entry(&engine->timeline->requests,
|
||||
struct drm_i915_gem_request, link);
|
||||
struct i915_request, link);
|
||||
if (&rq->link != &engine->timeline->requests)
|
||||
print_request(m, rq, "\t\tlast ");
|
||||
|
||||
|
@ -1903,6 +1949,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
|
|||
spin_lock_irq(&engine->timeline->lock);
|
||||
list_for_each_entry(rq, &engine->timeline->requests, link)
|
||||
print_request(m, rq, "\t\tE ");
|
||||
drm_printf(m, "\t\tQueue priority: %d\n", execlists->queue_priority);
|
||||
for (rb = execlists->first; rb; rb = rb_next(rb)) {
|
||||
struct i915_priolist *p =
|
||||
rb_entry(rb, typeof(*p), node);
|
||||
|
|
|
@ -46,16 +46,6 @@ static inline bool fbc_supported(struct drm_i915_private *dev_priv)
|
|||
return HAS_FBC(dev_priv);
|
||||
}
|
||||
|
||||
static inline bool fbc_on_pipe_a_only(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
return IS_HASWELL(dev_priv) || INTEL_GEN(dev_priv) >= 8;
|
||||
}
|
||||
|
||||
static inline bool fbc_on_plane_a_only(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
return INTEL_GEN(dev_priv) < 4;
|
||||
}
|
||||
|
||||
static inline bool no_fbc_on_multiple_pipes(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
return INTEL_GEN(dev_priv) <= 3;
|
||||
|
@ -819,6 +809,12 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
|
|||
* Note that is possible for a tiled surface to be unmappable (and
|
||||
* so have no fence associated with it) due to aperture constaints
|
||||
* at the time of pinning.
|
||||
*
|
||||
* FIXME with 90/270 degree rotation we should use the fence on
|
||||
* the normal GTT view (the rotated view doesn't even have a
|
||||
* fence). Would need changes to the FBC fence Y offset as well.
|
||||
* For now this will effecively disable FBC with 90/270 degree
|
||||
* rotation.
|
||||
*/
|
||||
if (!(cache->flags & PLANE_HAS_FENCE)) {
|
||||
fbc->no_fbc_reason = "framebuffer not tiled or fenced";
|
||||
|
@ -863,6 +859,17 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Work around a problem on GEN9+ HW, where enabling FBC on a plane
|
||||
* having a Y offset that isn't divisible by 4 causes FIFO underrun
|
||||
* and screen flicker.
|
||||
*/
|
||||
if (IS_GEN(dev_priv, 9, 10) &&
|
||||
(fbc->state_cache.plane.adjusted_y & 3)) {
|
||||
fbc->no_fbc_reason = "plane Y offset is misaligned";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -953,6 +960,30 @@ void intel_fbc_pre_update(struct intel_crtc *crtc,
|
|||
mutex_unlock(&fbc->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* __intel_fbc_disable - disable FBC
|
||||
* @dev_priv: i915 device instance
|
||||
*
|
||||
* This is the low level function that actually disables FBC. Callers should
|
||||
* grab the FBC lock.
|
||||
*/
|
||||
static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_fbc *fbc = &dev_priv->fbc;
|
||||
struct intel_crtc *crtc = fbc->crtc;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&fbc->lock));
|
||||
WARN_ON(!fbc->enabled);
|
||||
WARN_ON(fbc->active);
|
||||
|
||||
DRM_DEBUG_KMS("Disabling FBC on pipe %c\n", pipe_name(crtc->pipe));
|
||||
|
||||
__intel_fbc_cleanup_cfb(dev_priv);
|
||||
|
||||
fbc->enabled = false;
|
||||
fbc->crtc = NULL;
|
||||
}
|
||||
|
||||
static void __intel_fbc_post_update(struct intel_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
|
@ -964,6 +995,13 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc)
|
|||
if (!fbc->enabled || fbc->crtc != crtc)
|
||||
return;
|
||||
|
||||
if (!i915_modparams.enable_fbc) {
|
||||
intel_fbc_deactivate(dev_priv, "disabled at runtime per module param");
|
||||
__intel_fbc_disable(dev_priv);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!intel_fbc_can_activate(crtc)) {
|
||||
WARN_ON(fbc->active);
|
||||
return;
|
||||
|
@ -1094,15 +1132,12 @@ void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
|
|||
struct intel_crtc_state *crtc_state;
|
||||
struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc);
|
||||
|
||||
if (!plane->has_fbc)
|
||||
continue;
|
||||
|
||||
if (!plane_state->base.visible)
|
||||
continue;
|
||||
|
||||
if (fbc_on_pipe_a_only(dev_priv) && crtc->pipe != PIPE_A)
|
||||
continue;
|
||||
|
||||
if (fbc_on_plane_a_only(dev_priv) && plane->i9xx_plane != PLANE_A)
|
||||
continue;
|
||||
|
||||
crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
|
||||
|
||||
crtc_state->enable_fbc = true;
|
||||
|
@ -1170,31 +1205,6 @@ void intel_fbc_enable(struct intel_crtc *crtc,
|
|||
mutex_unlock(&fbc->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* __intel_fbc_disable - disable FBC
|
||||
* @dev_priv: i915 device instance
|
||||
*
|
||||
* This is the low level function that actually disables FBC. Callers should
|
||||
* grab the FBC lock.
|
||||
*/
|
||||
static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_fbc *fbc = &dev_priv->fbc;
|
||||
struct intel_crtc *crtc = fbc->crtc;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&fbc->lock));
|
||||
WARN_ON(!fbc->enabled);
|
||||
WARN_ON(fbc->active);
|
||||
WARN_ON(crtc->active);
|
||||
|
||||
DRM_DEBUG_KMS("Disabling FBC on pipe %c\n", pipe_name(crtc->pipe));
|
||||
|
||||
__intel_fbc_cleanup_cfb(dev_priv);
|
||||
|
||||
fbc->enabled = false;
|
||||
fbc->crtc = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_fbc_disable - disable FBC if it's associated with crtc
|
||||
* @crtc: the CRTC
|
||||
|
@ -1209,6 +1219,8 @@ void intel_fbc_disable(struct intel_crtc *crtc)
|
|||
if (!fbc_supported(dev_priv))
|
||||
return;
|
||||
|
||||
WARN_ON(crtc->active);
|
||||
|
||||
mutex_lock(&fbc->lock);
|
||||
if (fbc->crtc == crtc)
|
||||
__intel_fbc_disable(dev_priv);
|
||||
|
@ -1231,8 +1243,10 @@ void intel_fbc_global_disable(struct drm_i915_private *dev_priv)
|
|||
return;
|
||||
|
||||
mutex_lock(&fbc->lock);
|
||||
if (fbc->enabled)
|
||||
if (fbc->enabled) {
|
||||
WARN_ON(fbc->crtc->active);
|
||||
__intel_fbc_disable(dev_priv);
|
||||
}
|
||||
mutex_unlock(&fbc->lock);
|
||||
|
||||
cancel_work_sync(&fbc->work.work);
|
||||
|
@ -1357,7 +1371,6 @@ static bool need_fbc_vtd_wa(struct drm_i915_private *dev_priv)
|
|||
void intel_fbc_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_fbc *fbc = &dev_priv->fbc;
|
||||
enum pipe pipe;
|
||||
|
||||
INIT_WORK(&fbc->work.work, intel_fbc_work_fn);
|
||||
INIT_WORK(&fbc->underrun_work, intel_fbc_underrun_work_fn);
|
||||
|
@ -1378,14 +1391,6 @@ void intel_fbc_init(struct drm_i915_private *dev_priv)
|
|||
return;
|
||||
}
|
||||
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
fbc->possible_framebuffer_bits |=
|
||||
INTEL_FRONTBUFFER(pipe, PLANE_PRIMARY);
|
||||
|
||||
if (fbc_on_pipe_a_only(dev_priv))
|
||||
break;
|
||||
}
|
||||
|
||||
/* This value was pulled out of someone's hat */
|
||||
if (INTEL_GEN(dev_priv) <= 4 && !IS_GM45(dev_priv))
|
||||
I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
|
||||
|
|
|
@ -215,7 +215,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
|
|||
*/
|
||||
vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base,
|
||||
DRM_MODE_ROTATE_0,
|
||||
&flags);
|
||||
false, &flags);
|
||||
if (IS_ERR(vma)) {
|
||||
ret = PTR_ERR(vma);
|
||||
goto out_unlock;
|
||||
|
|
|
@ -79,6 +79,7 @@ void __intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
|
|||
spin_unlock(&dev_priv->fb_tracking.lock);
|
||||
}
|
||||
|
||||
might_sleep();
|
||||
intel_psr_invalidate(dev_priv, frontbuffer_bits);
|
||||
intel_edp_drrs_invalidate(dev_priv, frontbuffer_bits);
|
||||
intel_fbc_invalidate(dev_priv, frontbuffer_bits, origin);
|
||||
|
@ -108,6 +109,7 @@ static void intel_frontbuffer_flush(struct drm_i915_private *dev_priv,
|
|||
if (!frontbuffer_bits)
|
||||
return;
|
||||
|
||||
might_sleep();
|
||||
intel_edp_drrs_flush(dev_priv, frontbuffer_bits);
|
||||
intel_psr_flush(dev_priv, frontbuffer_bits, origin);
|
||||
intel_fbc_flush(dev_priv, frontbuffer_bits, origin);
|
||||
|
|
|
@ -370,7 +370,7 @@ int intel_guc_sample_forcewake(struct intel_guc *guc)
|
|||
u32 action[2];
|
||||
|
||||
action[0] = INTEL_GUC_ACTION_SAMPLE_FORCEWAKE;
|
||||
/* WaRsDisableCoarsePowerGating:skl,bxt */
|
||||
/* WaRsDisableCoarsePowerGating:skl,cnl */
|
||||
if (!HAS_RC6(dev_priv) || NEEDS_WaRsDisableCoarsePowerGating(dev_priv))
|
||||
action[1] = 0;
|
||||
else
|
||||
|
@ -403,22 +403,15 @@ int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset)
|
|||
|
||||
/**
|
||||
* intel_guc_suspend() - notify GuC entering suspend state
|
||||
* @dev_priv: i915 device private
|
||||
* @guc: the guc
|
||||
*/
|
||||
int intel_guc_suspend(struct drm_i915_private *dev_priv)
|
||||
int intel_guc_suspend(struct intel_guc *guc)
|
||||
{
|
||||
struct intel_guc *guc = &dev_priv->guc;
|
||||
u32 data[3];
|
||||
|
||||
if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
|
||||
return 0;
|
||||
|
||||
gen9_disable_guc_interrupts(dev_priv);
|
||||
|
||||
data[0] = INTEL_GUC_ACTION_ENTER_S_STATE;
|
||||
/* any value greater than GUC_POWER_D0 */
|
||||
data[1] = GUC_POWER_D1;
|
||||
data[2] = guc_ggtt_offset(guc->shared_data);
|
||||
u32 data[] = {
|
||||
INTEL_GUC_ACTION_ENTER_S_STATE,
|
||||
GUC_POWER_D1, /* any value greater than GUC_POWER_D0 */
|
||||
guc_ggtt_offset(guc->shared_data)
|
||||
};
|
||||
|
||||
return intel_guc_send(guc, data, ARRAY_SIZE(data));
|
||||
}
|
||||
|
@ -448,22 +441,15 @@ int intel_guc_reset_engine(struct intel_guc *guc,
|
|||
|
||||
/**
|
||||
* intel_guc_resume() - notify GuC resuming from suspend state
|
||||
* @dev_priv: i915 device private
|
||||
* @guc: the guc
|
||||
*/
|
||||
int intel_guc_resume(struct drm_i915_private *dev_priv)
|
||||
int intel_guc_resume(struct intel_guc *guc)
|
||||
{
|
||||
struct intel_guc *guc = &dev_priv->guc;
|
||||
u32 data[3];
|
||||
|
||||
if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
|
||||
return 0;
|
||||
|
||||
if (i915_modparams.guc_log_level)
|
||||
gen9_enable_guc_interrupts(dev_priv);
|
||||
|
||||
data[0] = INTEL_GUC_ACTION_EXIT_S_STATE;
|
||||
data[1] = GUC_POWER_D0;
|
||||
data[2] = guc_ggtt_offset(guc->shared_data);
|
||||
u32 data[] = {
|
||||
INTEL_GUC_ACTION_EXIT_S_STATE,
|
||||
GUC_POWER_D0,
|
||||
guc_ggtt_offset(guc->shared_data)
|
||||
};
|
||||
|
||||
return intel_guc_send(guc, data, ARRAY_SIZE(data));
|
||||
}
|
||||
|
|
|
@ -127,8 +127,8 @@ int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len);
|
|||
int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len);
|
||||
int intel_guc_sample_forcewake(struct intel_guc *guc);
|
||||
int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset);
|
||||
int intel_guc_suspend(struct drm_i915_private *dev_priv);
|
||||
int intel_guc_resume(struct drm_i915_private *dev_priv);
|
||||
int intel_guc_suspend(struct intel_guc *guc);
|
||||
int intel_guc_resume(struct intel_guc *guc);
|
||||
struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size);
|
||||
u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv);
|
||||
|
||||
|
|
|
@ -269,15 +269,15 @@ static int guc_fw_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma)
|
|||
}
|
||||
|
||||
/**
|
||||
* intel_guc_fw_upload() - finish preparing the GuC for activity
|
||||
* intel_guc_fw_upload() - load GuC uCode to device
|
||||
* @guc: intel_guc structure
|
||||
*
|
||||
* Called during driver loading and also after a GPU reset.
|
||||
* Called from intel_uc_init_hw() during driver load, resume from sleep and
|
||||
* after a GPU reset.
|
||||
*
|
||||
* The main action required here it to load the GuC uCode into the device.
|
||||
* The firmware image should have already been fetched into memory by the
|
||||
* earlier call to intel_guc_init(), so here we need only check that
|
||||
* worked, and then transfer the image to the h/w.
|
||||
* earlier call to intel_uc_init_fw(), so here we need to only check that
|
||||
* fetch succeeded, and then transfer the image to the h/w.
|
||||
*
|
||||
* Return: non-zero code on error
|
||||
*/
|
||||
|
|
|
@ -61,8 +61,10 @@ static int guc_log_flush(struct intel_guc *guc)
|
|||
static int guc_log_control(struct intel_guc *guc, bool enable, u32 verbosity)
|
||||
{
|
||||
union guc_log_control control_val = {
|
||||
.logging_enabled = enable,
|
||||
.verbosity = verbosity,
|
||||
{
|
||||
.logging_enabled = enable,
|
||||
.verbosity = verbosity,
|
||||
},
|
||||
};
|
||||
u32 action[] = {
|
||||
INTEL_GUC_ACTION_UK_LOG_ENABLE_LOGGING,
|
||||
|
|
|
@ -26,8 +26,14 @@
|
|||
#include <trace/events/dma_fence.h>
|
||||
|
||||
#include "intel_guc_submission.h"
|
||||
#include "intel_lrc_reg.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
#define GUC_PREEMPT_FINISHED 0x1
|
||||
#define GUC_PREEMPT_BREADCRUMB_DWORDS 0x8
|
||||
#define GUC_PREEMPT_BREADCRUMB_BYTES \
|
||||
(sizeof(u32) * GUC_PREEMPT_BREADCRUMB_DWORDS)
|
||||
|
||||
/**
|
||||
* DOC: GuC-based command submission
|
||||
*
|
||||
|
@ -75,6 +81,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
static inline struct i915_priolist *to_priolist(struct rb_node *rb)
|
||||
{
|
||||
return rb_entry(rb, struct i915_priolist, node);
|
||||
}
|
||||
|
||||
static inline bool is_high_priority(struct intel_guc_client *client)
|
||||
{
|
||||
return (client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH ||
|
||||
|
@ -496,8 +507,7 @@ static void guc_ring_doorbell(struct intel_guc_client *client)
|
|||
GEM_BUG_ON(db->db_status != GUC_DOORBELL_ENABLED);
|
||||
}
|
||||
|
||||
static void guc_add_request(struct intel_guc *guc,
|
||||
struct drm_i915_gem_request *rq)
|
||||
static void guc_add_request(struct intel_guc *guc, struct i915_request *rq)
|
||||
{
|
||||
struct intel_guc_client *client = guc->execbuf_client;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
|
@ -531,8 +541,6 @@ static void flush_ggtt_writes(struct i915_vma *vma)
|
|||
POSTING_READ_FW(GUC_STATUS);
|
||||
}
|
||||
|
||||
#define GUC_PREEMPT_FINISHED 0x1
|
||||
#define GUC_PREEMPT_BREADCRUMB_DWORDS 0x8
|
||||
static void inject_preempt_context(struct work_struct *work)
|
||||
{
|
||||
struct guc_preempt_work *preempt_work =
|
||||
|
@ -542,37 +550,17 @@ static void inject_preempt_context(struct work_struct *work)
|
|||
preempt_work[engine->id]);
|
||||
struct intel_guc_client *client = guc->preempt_client;
|
||||
struct guc_stage_desc *stage_desc = __get_stage_desc(client);
|
||||
struct intel_ring *ring = client->owner->engine[engine->id].ring;
|
||||
u32 ctx_desc = lower_32_bits(intel_lr_context_descriptor(client->owner,
|
||||
engine));
|
||||
u32 *cs = ring->vaddr + ring->tail;
|
||||
u32 data[7];
|
||||
|
||||
if (engine->id == RCS) {
|
||||
cs = gen8_emit_ggtt_write_rcs(cs, GUC_PREEMPT_FINISHED,
|
||||
intel_hws_preempt_done_address(engine));
|
||||
} else {
|
||||
cs = gen8_emit_ggtt_write(cs, GUC_PREEMPT_FINISHED,
|
||||
intel_hws_preempt_done_address(engine));
|
||||
*cs++ = MI_NOOP;
|
||||
*cs++ = MI_NOOP;
|
||||
}
|
||||
*cs++ = MI_USER_INTERRUPT;
|
||||
*cs++ = MI_NOOP;
|
||||
|
||||
GEM_BUG_ON(!IS_ALIGNED(ring->size,
|
||||
GUC_PREEMPT_BREADCRUMB_DWORDS * sizeof(u32)));
|
||||
GEM_BUG_ON((void *)cs - (ring->vaddr + ring->tail) !=
|
||||
GUC_PREEMPT_BREADCRUMB_DWORDS * sizeof(u32));
|
||||
|
||||
ring->tail += GUC_PREEMPT_BREADCRUMB_DWORDS * sizeof(u32);
|
||||
ring->tail &= (ring->size - 1);
|
||||
|
||||
flush_ggtt_writes(ring->vma);
|
||||
|
||||
/*
|
||||
* The ring contains commands to write GUC_PREEMPT_FINISHED into HWSP.
|
||||
* See guc_fill_preempt_context().
|
||||
*/
|
||||
spin_lock_irq(&client->wq_lock);
|
||||
guc_wq_item_append(client, engine->guc_id, ctx_desc,
|
||||
ring->tail / sizeof(u64), 0);
|
||||
GUC_PREEMPT_BREADCRUMB_BYTES / sizeof(u64), 0);
|
||||
spin_unlock_irq(&client->wq_lock);
|
||||
|
||||
/*
|
||||
|
@ -648,7 +636,7 @@ static void guc_submit(struct intel_engine_cs *engine)
|
|||
unsigned int n;
|
||||
|
||||
for (n = 0; n < execlists_num_ports(execlists); n++) {
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
unsigned int count;
|
||||
|
||||
rq = port_unpack(&port[n], &count);
|
||||
|
@ -662,19 +650,18 @@ static void guc_submit(struct intel_engine_cs *engine)
|
|||
}
|
||||
}
|
||||
|
||||
static void port_assign(struct execlist_port *port,
|
||||
struct drm_i915_gem_request *rq)
|
||||
static void port_assign(struct execlist_port *port, struct i915_request *rq)
|
||||
{
|
||||
GEM_BUG_ON(port_isset(port));
|
||||
|
||||
port_set(port, i915_gem_request_get(rq));
|
||||
port_set(port, i915_request_get(rq));
|
||||
}
|
||||
|
||||
static void guc_dequeue(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct intel_engine_execlists * const execlists = &engine->execlists;
|
||||
struct execlist_port *port = execlists->port;
|
||||
struct drm_i915_gem_request *last = NULL;
|
||||
struct i915_request *last = NULL;
|
||||
const struct execlist_port * const last_port =
|
||||
&execlists->port[execlists->port_mask];
|
||||
bool submit = false;
|
||||
|
@ -684,15 +671,12 @@ static void guc_dequeue(struct intel_engine_cs *engine)
|
|||
rb = execlists->first;
|
||||
GEM_BUG_ON(rb_first(&execlists->queue) != rb);
|
||||
|
||||
if (!rb)
|
||||
goto unlock;
|
||||
|
||||
if (port_isset(port)) {
|
||||
if (engine->i915->preempt_context) {
|
||||
struct guc_preempt_work *preempt_work =
|
||||
&engine->i915->guc.preempt_work[engine->id];
|
||||
|
||||
if (rb_entry(rb, struct i915_priolist, node)->priority >
|
||||
if (execlists->queue_priority >
|
||||
max(port_request(port)->priotree.priority, 0)) {
|
||||
execlists_set_active(execlists,
|
||||
EXECLISTS_ACTIVE_PREEMPT);
|
||||
|
@ -708,9 +692,9 @@ static void guc_dequeue(struct intel_engine_cs *engine)
|
|||
}
|
||||
GEM_BUG_ON(port_isset(port));
|
||||
|
||||
do {
|
||||
struct i915_priolist *p = rb_entry(rb, typeof(*p), node);
|
||||
struct drm_i915_gem_request *rq, *rn;
|
||||
while (rb) {
|
||||
struct i915_priolist *p = to_priolist(rb);
|
||||
struct i915_request *rq, *rn;
|
||||
|
||||
list_for_each_entry_safe(rq, rn, &p->requests, priotree.link) {
|
||||
if (last && rq->ctx != last->ctx) {
|
||||
|
@ -727,9 +711,8 @@ static void guc_dequeue(struct intel_engine_cs *engine)
|
|||
|
||||
INIT_LIST_HEAD(&rq->priotree.link);
|
||||
|
||||
__i915_gem_request_submit(rq);
|
||||
trace_i915_gem_request_in(rq,
|
||||
port_index(port, execlists));
|
||||
__i915_request_submit(rq);
|
||||
trace_i915_request_in(rq, port_index(port, execlists));
|
||||
last = rq;
|
||||
submit = true;
|
||||
}
|
||||
|
@ -739,8 +722,9 @@ static void guc_dequeue(struct intel_engine_cs *engine)
|
|||
INIT_LIST_HEAD(&p->requests);
|
||||
if (p->priority != I915_PRIORITY_NORMAL)
|
||||
kmem_cache_free(engine->i915->priorities, p);
|
||||
} while (rb);
|
||||
}
|
||||
done:
|
||||
execlists->queue_priority = rb ? to_priolist(rb)->priority : INT_MIN;
|
||||
execlists->first = rb;
|
||||
if (submit) {
|
||||
port_assign(port, last);
|
||||
|
@ -762,12 +746,12 @@ static void guc_submission_tasklet(unsigned long data)
|
|||
struct intel_engine_cs * const engine = (struct intel_engine_cs *)data;
|
||||
struct intel_engine_execlists * const execlists = &engine->execlists;
|
||||
struct execlist_port *port = execlists->port;
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
|
||||
rq = port_request(&port[0]);
|
||||
while (rq && i915_gem_request_completed(rq)) {
|
||||
trace_i915_gem_request_out(rq);
|
||||
i915_gem_request_put(rq);
|
||||
while (rq && i915_request_completed(rq)) {
|
||||
trace_i915_request_out(rq);
|
||||
i915_request_put(rq);
|
||||
|
||||
execlists_port_complete(execlists, port);
|
||||
|
||||
|
@ -972,6 +956,62 @@ static void guc_client_free(struct intel_guc_client *client)
|
|||
kfree(client);
|
||||
}
|
||||
|
||||
static inline bool ctx_save_restore_disabled(struct intel_context *ce)
|
||||
{
|
||||
u32 sr = ce->lrc_reg_state[CTX_CONTEXT_CONTROL + 1];
|
||||
|
||||
#define SR_DISABLED \
|
||||
_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | \
|
||||
CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT)
|
||||
|
||||
return (sr & SR_DISABLED) == SR_DISABLED;
|
||||
|
||||
#undef SR_DISABLED
|
||||
}
|
||||
|
||||
static void guc_fill_preempt_context(struct intel_guc *guc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = guc_to_i915(guc);
|
||||
struct intel_guc_client *client = guc->preempt_client;
|
||||
struct intel_engine_cs *engine;
|
||||
enum intel_engine_id id;
|
||||
|
||||
for_each_engine(engine, dev_priv, id) {
|
||||
struct intel_context *ce = &client->owner->engine[id];
|
||||
u32 addr = intel_hws_preempt_done_address(engine);
|
||||
u32 *cs;
|
||||
|
||||
GEM_BUG_ON(!ce->pin_count);
|
||||
|
||||
/*
|
||||
* We rely on this context image *not* being saved after
|
||||
* preemption. This ensures that the RING_HEAD / RING_TAIL
|
||||
* remain pointing at initial values forever.
|
||||
*/
|
||||
GEM_BUG_ON(!ctx_save_restore_disabled(ce));
|
||||
|
||||
cs = ce->ring->vaddr;
|
||||
if (id == RCS) {
|
||||
cs = gen8_emit_ggtt_write_rcs(cs,
|
||||
GUC_PREEMPT_FINISHED,
|
||||
addr);
|
||||
} else {
|
||||
cs = gen8_emit_ggtt_write(cs,
|
||||
GUC_PREEMPT_FINISHED,
|
||||
addr);
|
||||
*cs++ = MI_NOOP;
|
||||
*cs++ = MI_NOOP;
|
||||
}
|
||||
*cs++ = MI_USER_INTERRUPT;
|
||||
*cs++ = MI_NOOP;
|
||||
|
||||
GEM_BUG_ON((void *)cs - ce->ring->vaddr !=
|
||||
GUC_PREEMPT_BREADCRUMB_BYTES);
|
||||
|
||||
flush_ggtt_writes(ce->ring->vma);
|
||||
}
|
||||
}
|
||||
|
||||
static int guc_clients_create(struct intel_guc *guc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = guc_to_i915(guc);
|
||||
|
@ -1002,6 +1042,8 @@ static int guc_clients_create(struct intel_guc *guc)
|
|||
return PTR_ERR(client);
|
||||
}
|
||||
guc->preempt_client = client;
|
||||
|
||||
guc_fill_preempt_context(guc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -2383,6 +2383,7 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
|
|||
&intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
|
||||
"HDMI %c", port_name(port));
|
||||
|
||||
intel_encoder->hotplug = intel_encoder_hotplug;
|
||||
intel_encoder->compute_config = intel_hdmi_compute_config;
|
||||
if (HAS_PCH_SPLIT(dev_priv)) {
|
||||
intel_encoder->disable = pch_disable_hdmi;
|
||||
|
|
|
@ -274,24 +274,26 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
|
|||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
static bool intel_hpd_irq_event(struct drm_device *dev,
|
||||
struct drm_connector *connector)
|
||||
bool intel_encoder_hotplug(struct intel_encoder *encoder,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->base.dev;
|
||||
enum drm_connector_status old_status;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
||||
old_status = connector->status;
|
||||
old_status = connector->base.status;
|
||||
|
||||
connector->status = drm_helper_probe_detect(connector, NULL, false);
|
||||
connector->base.status =
|
||||
drm_helper_probe_detect(&connector->base, NULL, false);
|
||||
|
||||
if (old_status == connector->status)
|
||||
if (old_status == connector->base.status)
|
||||
return false;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
|
||||
connector->base.id,
|
||||
connector->name,
|
||||
connector->base.base.id,
|
||||
connector->base.name,
|
||||
drm_get_connector_status_name(old_status),
|
||||
drm_get_connector_status_name(connector->status));
|
||||
drm_get_connector_status_name(connector->base.status));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -381,10 +383,9 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
|||
if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
|
||||
DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
|
||||
connector->name, intel_encoder->hpd_pin);
|
||||
if (intel_encoder->hot_plug)
|
||||
intel_encoder->hot_plug(intel_encoder);
|
||||
if (intel_hpd_irq_event(dev, connector))
|
||||
changed = true;
|
||||
|
||||
changed |= intel_encoder->hotplug(intel_encoder,
|
||||
intel_connector);
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
|
|
@ -27,161 +27,9 @@
|
|||
#include "intel_huc.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
/**
|
||||
* DOC: HuC Firmware
|
||||
*
|
||||
* Motivation:
|
||||
* GEN9 introduces a new dedicated firmware for usage in media HEVC (High
|
||||
* Efficiency Video Coding) operations. Userspace can use the firmware
|
||||
* capabilities by adding HuC specific commands to batch buffers.
|
||||
*
|
||||
* Implementation:
|
||||
* The same firmware loader is used as the GuC. However, the actual
|
||||
* loading to HW is deferred until GEM initialization is done.
|
||||
*
|
||||
* Note that HuC firmware loading must be done before GuC loading.
|
||||
*/
|
||||
|
||||
#define BXT_HUC_FW_MAJOR 01
|
||||
#define BXT_HUC_FW_MINOR 07
|
||||
#define BXT_BLD_NUM 1398
|
||||
|
||||
#define SKL_HUC_FW_MAJOR 01
|
||||
#define SKL_HUC_FW_MINOR 07
|
||||
#define SKL_BLD_NUM 1398
|
||||
|
||||
#define KBL_HUC_FW_MAJOR 02
|
||||
#define KBL_HUC_FW_MINOR 00
|
||||
#define KBL_BLD_NUM 1810
|
||||
|
||||
#define HUC_FW_PATH(platform, major, minor, bld_num) \
|
||||
"i915/" __stringify(platform) "_huc_ver" __stringify(major) "_" \
|
||||
__stringify(minor) "_" __stringify(bld_num) ".bin"
|
||||
|
||||
#define I915_SKL_HUC_UCODE HUC_FW_PATH(skl, SKL_HUC_FW_MAJOR, \
|
||||
SKL_HUC_FW_MINOR, SKL_BLD_NUM)
|
||||
MODULE_FIRMWARE(I915_SKL_HUC_UCODE);
|
||||
|
||||
#define I915_BXT_HUC_UCODE HUC_FW_PATH(bxt, BXT_HUC_FW_MAJOR, \
|
||||
BXT_HUC_FW_MINOR, BXT_BLD_NUM)
|
||||
MODULE_FIRMWARE(I915_BXT_HUC_UCODE);
|
||||
|
||||
#define I915_KBL_HUC_UCODE HUC_FW_PATH(kbl, KBL_HUC_FW_MAJOR, \
|
||||
KBL_HUC_FW_MINOR, KBL_BLD_NUM)
|
||||
MODULE_FIRMWARE(I915_KBL_HUC_UCODE);
|
||||
|
||||
static void huc_fw_select(struct intel_uc_fw *huc_fw)
|
||||
{
|
||||
struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw);
|
||||
struct drm_i915_private *dev_priv = huc_to_i915(huc);
|
||||
|
||||
GEM_BUG_ON(huc_fw->type != INTEL_UC_FW_TYPE_HUC);
|
||||
|
||||
if (!HAS_HUC(dev_priv))
|
||||
return;
|
||||
|
||||
if (i915_modparams.huc_firmware_path) {
|
||||
huc_fw->path = i915_modparams.huc_firmware_path;
|
||||
huc_fw->major_ver_wanted = 0;
|
||||
huc_fw->minor_ver_wanted = 0;
|
||||
} else if (IS_SKYLAKE(dev_priv)) {
|
||||
huc_fw->path = I915_SKL_HUC_UCODE;
|
||||
huc_fw->major_ver_wanted = SKL_HUC_FW_MAJOR;
|
||||
huc_fw->minor_ver_wanted = SKL_HUC_FW_MINOR;
|
||||
} else if (IS_BROXTON(dev_priv)) {
|
||||
huc_fw->path = I915_BXT_HUC_UCODE;
|
||||
huc_fw->major_ver_wanted = BXT_HUC_FW_MAJOR;
|
||||
huc_fw->minor_ver_wanted = BXT_HUC_FW_MINOR;
|
||||
} else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) {
|
||||
huc_fw->path = I915_KBL_HUC_UCODE;
|
||||
huc_fw->major_ver_wanted = KBL_HUC_FW_MAJOR;
|
||||
huc_fw->minor_ver_wanted = KBL_HUC_FW_MINOR;
|
||||
} else {
|
||||
DRM_WARN("%s: No firmware known for this platform!\n",
|
||||
intel_uc_fw_type_repr(huc_fw->type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_huc_init_early() - initializes HuC struct
|
||||
* @huc: intel_huc struct
|
||||
*
|
||||
* On platforms with HuC selects firmware for uploading
|
||||
*/
|
||||
void intel_huc_init_early(struct intel_huc *huc)
|
||||
{
|
||||
struct intel_uc_fw *huc_fw = &huc->fw;
|
||||
|
||||
intel_uc_fw_init(huc_fw, INTEL_UC_FW_TYPE_HUC);
|
||||
huc_fw_select(huc_fw);
|
||||
}
|
||||
|
||||
/**
|
||||
* huc_ucode_xfer() - DMA's the firmware
|
||||
* @huc_fw: the firmware descriptor
|
||||
* @vma: the firmware image (bound into the GGTT)
|
||||
*
|
||||
* Transfer the firmware image to RAM for execution by the microcontroller.
|
||||
*
|
||||
* Return: 0 on success, non-zero on failure
|
||||
*/
|
||||
static int huc_ucode_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma)
|
||||
{
|
||||
struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw);
|
||||
struct drm_i915_private *dev_priv = huc_to_i915(huc);
|
||||
unsigned long offset = 0;
|
||||
u32 size;
|
||||
int ret;
|
||||
|
||||
GEM_BUG_ON(huc_fw->type != INTEL_UC_FW_TYPE_HUC);
|
||||
|
||||
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
|
||||
|
||||
/* Set the source address for the uCode */
|
||||
offset = guc_ggtt_offset(vma) + huc_fw->header_offset;
|
||||
I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
|
||||
I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
|
||||
|
||||
/* Hardware doesn't look at destination address for HuC. Set it to 0,
|
||||
* but still program the correct address space.
|
||||
*/
|
||||
I915_WRITE(DMA_ADDR_1_LOW, 0);
|
||||
I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
|
||||
|
||||
size = huc_fw->header_size + huc_fw->ucode_size;
|
||||
I915_WRITE(DMA_COPY_SIZE, size);
|
||||
|
||||
/* Start the DMA */
|
||||
I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(HUC_UKERNEL | START_DMA));
|
||||
|
||||
/* Wait for DMA to finish */
|
||||
ret = intel_wait_for_register_fw(dev_priv, DMA_CTRL, START_DMA, 0, 100);
|
||||
|
||||
DRM_DEBUG_DRIVER("HuC DMA transfer wait over with ret %d\n", ret);
|
||||
|
||||
/* Disable the bits once DMA is over */
|
||||
I915_WRITE(DMA_CTRL, _MASKED_BIT_DISABLE(HUC_UKERNEL));
|
||||
|
||||
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_huc_init_hw() - load HuC uCode to device
|
||||
* @huc: intel_huc structure
|
||||
*
|
||||
* Called from intel_uc_init_hw() during driver loading and also after a GPU
|
||||
* reset. Be note that HuC loading must be done before GuC loading.
|
||||
*
|
||||
* The firmware image should have already been fetched into memory by the
|
||||
* earlier call to intel_uc_init_fw(), so here we need only check that
|
||||
* is succeeded, and then transfer the image to the h/w.
|
||||
*
|
||||
*/
|
||||
int intel_huc_init_hw(struct intel_huc *huc)
|
||||
{
|
||||
return intel_uc_fw_upload(&huc->fw, huc_ucode_xfer);
|
||||
intel_huc_fw_init_early(huc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,6 +48,7 @@ int intel_huc_auth(struct intel_huc *huc)
|
|||
struct drm_i915_private *i915 = huc_to_i915(huc);
|
||||
struct intel_guc *guc = &i915->guc;
|
||||
struct i915_vma *vma;
|
||||
u32 status;
|
||||
int ret;
|
||||
|
||||
if (huc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
|
||||
|
@ -210,28 +59,35 @@ int intel_huc_auth(struct intel_huc *huc)
|
|||
if (IS_ERR(vma)) {
|
||||
ret = PTR_ERR(vma);
|
||||
DRM_ERROR("HuC: Failed to pin huc fw object %d\n", ret);
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = intel_guc_auth_huc(guc,
|
||||
guc_ggtt_offset(vma) + huc->fw.rsa_offset);
|
||||
if (ret) {
|
||||
DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret);
|
||||
goto out;
|
||||
goto fail_unpin;
|
||||
}
|
||||
|
||||
/* Check authentication status, it should be done by now */
|
||||
ret = intel_wait_for_register(i915,
|
||||
HUC_STATUS2,
|
||||
HUC_FW_VERIFIED,
|
||||
HUC_FW_VERIFIED,
|
||||
50);
|
||||
ret = __intel_wait_for_register(i915,
|
||||
HUC_STATUS2,
|
||||
HUC_FW_VERIFIED,
|
||||
HUC_FW_VERIFIED,
|
||||
2, 50, &status);
|
||||
if (ret) {
|
||||
DRM_ERROR("HuC: Authentication failed %d\n", ret);
|
||||
goto out;
|
||||
DRM_ERROR("HuC: Firmware not verified %#x\n", status);
|
||||
goto fail_unpin;
|
||||
}
|
||||
|
||||
out:
|
||||
i915_vma_unpin(vma);
|
||||
return 0;
|
||||
|
||||
fail_unpin:
|
||||
i915_vma_unpin(vma);
|
||||
fail:
|
||||
huc->fw.load_status = INTEL_UC_FIRMWARE_FAIL;
|
||||
|
||||
DRM_ERROR("HuC: Authentication failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#define _INTEL_HUC_H_
|
||||
|
||||
#include "intel_uc_fw.h"
|
||||
#include "intel_huc_fw.h"
|
||||
|
||||
struct intel_huc {
|
||||
/* Generic uC firmware management */
|
||||
|
@ -35,7 +36,6 @@ struct intel_huc {
|
|||
};
|
||||
|
||||
void intel_huc_init_early(struct intel_huc *huc);
|
||||
int intel_huc_init_hw(struct intel_huc *huc);
|
||||
int intel_huc_auth(struct intel_huc *huc);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright © 2014-2018 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "intel_huc_fw.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
/**
|
||||
* DOC: HuC Firmware
|
||||
*
|
||||
* Motivation:
|
||||
* GEN9 introduces a new dedicated firmware for usage in media HEVC (High
|
||||
* Efficiency Video Coding) operations. Userspace can use the firmware
|
||||
* capabilities by adding HuC specific commands to batch buffers.
|
||||
*
|
||||
* Implementation:
|
||||
* The same firmware loader is used as the GuC. However, the actual
|
||||
* loading to HW is deferred until GEM initialization is done.
|
||||
*
|
||||
* Note that HuC firmware loading must be done before GuC loading.
|
||||
*/
|
||||
|
||||
#define BXT_HUC_FW_MAJOR 01
|
||||
#define BXT_HUC_FW_MINOR 07
|
||||
#define BXT_BLD_NUM 1398
|
||||
|
||||
#define SKL_HUC_FW_MAJOR 01
|
||||
#define SKL_HUC_FW_MINOR 07
|
||||
#define SKL_BLD_NUM 1398
|
||||
|
||||
#define KBL_HUC_FW_MAJOR 02
|
||||
#define KBL_HUC_FW_MINOR 00
|
||||
#define KBL_BLD_NUM 1810
|
||||
|
||||
#define HUC_FW_PATH(platform, major, minor, bld_num) \
|
||||
"i915/" __stringify(platform) "_huc_ver" __stringify(major) "_" \
|
||||
__stringify(minor) "_" __stringify(bld_num) ".bin"
|
||||
|
||||
#define I915_SKL_HUC_UCODE HUC_FW_PATH(skl, SKL_HUC_FW_MAJOR, \
|
||||
SKL_HUC_FW_MINOR, SKL_BLD_NUM)
|
||||
MODULE_FIRMWARE(I915_SKL_HUC_UCODE);
|
||||
|
||||
#define I915_BXT_HUC_UCODE HUC_FW_PATH(bxt, BXT_HUC_FW_MAJOR, \
|
||||
BXT_HUC_FW_MINOR, BXT_BLD_NUM)
|
||||
MODULE_FIRMWARE(I915_BXT_HUC_UCODE);
|
||||
|
||||
#define I915_KBL_HUC_UCODE HUC_FW_PATH(kbl, KBL_HUC_FW_MAJOR, \
|
||||
KBL_HUC_FW_MINOR, KBL_BLD_NUM)
|
||||
MODULE_FIRMWARE(I915_KBL_HUC_UCODE);
|
||||
|
||||
static void huc_fw_select(struct intel_uc_fw *huc_fw)
|
||||
{
|
||||
struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw);
|
||||
struct drm_i915_private *dev_priv = huc_to_i915(huc);
|
||||
|
||||
GEM_BUG_ON(huc_fw->type != INTEL_UC_FW_TYPE_HUC);
|
||||
|
||||
if (!HAS_HUC(dev_priv))
|
||||
return;
|
||||
|
||||
if (i915_modparams.huc_firmware_path) {
|
||||
huc_fw->path = i915_modparams.huc_firmware_path;
|
||||
huc_fw->major_ver_wanted = 0;
|
||||
huc_fw->minor_ver_wanted = 0;
|
||||
} else if (IS_SKYLAKE(dev_priv)) {
|
||||
huc_fw->path = I915_SKL_HUC_UCODE;
|
||||
huc_fw->major_ver_wanted = SKL_HUC_FW_MAJOR;
|
||||
huc_fw->minor_ver_wanted = SKL_HUC_FW_MINOR;
|
||||
} else if (IS_BROXTON(dev_priv)) {
|
||||
huc_fw->path = I915_BXT_HUC_UCODE;
|
||||
huc_fw->major_ver_wanted = BXT_HUC_FW_MAJOR;
|
||||
huc_fw->minor_ver_wanted = BXT_HUC_FW_MINOR;
|
||||
} else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) {
|
||||
huc_fw->path = I915_KBL_HUC_UCODE;
|
||||
huc_fw->major_ver_wanted = KBL_HUC_FW_MAJOR;
|
||||
huc_fw->minor_ver_wanted = KBL_HUC_FW_MINOR;
|
||||
} else {
|
||||
DRM_WARN("%s: No firmware known for this platform!\n",
|
||||
intel_uc_fw_type_repr(huc_fw->type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_huc_fw_init_early() - initializes HuC firmware struct
|
||||
* @huc: intel_huc struct
|
||||
*
|
||||
* On platforms with HuC selects firmware for uploading
|
||||
*/
|
||||
void intel_huc_fw_init_early(struct intel_huc *huc)
|
||||
{
|
||||
struct intel_uc_fw *huc_fw = &huc->fw;
|
||||
|
||||
intel_uc_fw_init(huc_fw, INTEL_UC_FW_TYPE_HUC);
|
||||
huc_fw_select(huc_fw);
|
||||
}
|
||||
|
||||
/**
|
||||
* huc_fw_xfer() - DMA's the firmware
|
||||
* @huc_fw: the firmware descriptor
|
||||
* @vma: the firmware image (bound into the GGTT)
|
||||
*
|
||||
* Transfer the firmware image to RAM for execution by the microcontroller.
|
||||
*
|
||||
* Return: 0 on success, non-zero on failure
|
||||
*/
|
||||
static int huc_fw_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma)
|
||||
{
|
||||
struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw);
|
||||
struct drm_i915_private *dev_priv = huc_to_i915(huc);
|
||||
unsigned long offset = 0;
|
||||
u32 size;
|
||||
int ret;
|
||||
|
||||
GEM_BUG_ON(huc_fw->type != INTEL_UC_FW_TYPE_HUC);
|
||||
|
||||
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
|
||||
|
||||
/* Set the source address for the uCode */
|
||||
offset = guc_ggtt_offset(vma) + huc_fw->header_offset;
|
||||
I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
|
||||
I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
|
||||
|
||||
/* Hardware doesn't look at destination address for HuC. Set it to 0,
|
||||
* but still program the correct address space.
|
||||
*/
|
||||
I915_WRITE(DMA_ADDR_1_LOW, 0);
|
||||
I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
|
||||
|
||||
size = huc_fw->header_size + huc_fw->ucode_size;
|
||||
I915_WRITE(DMA_COPY_SIZE, size);
|
||||
|
||||
/* Start the DMA */
|
||||
I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(HUC_UKERNEL | START_DMA));
|
||||
|
||||
/* Wait for DMA to finish */
|
||||
ret = intel_wait_for_register_fw(dev_priv, DMA_CTRL, START_DMA, 0, 100);
|
||||
|
||||
DRM_DEBUG_DRIVER("HuC DMA transfer wait over with ret %d\n", ret);
|
||||
|
||||
/* Disable the bits once DMA is over */
|
||||
I915_WRITE(DMA_CTRL, _MASKED_BIT_DISABLE(HUC_UKERNEL));
|
||||
|
||||
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_huc_fw_upload() - load HuC uCode to device
|
||||
* @huc: intel_huc structure
|
||||
*
|
||||
* Called from intel_uc_init_hw() during driver load, resume from sleep and
|
||||
* after a GPU reset. Note that HuC must be loaded before GuC.
|
||||
*
|
||||
* The firmware image should have already been fetched into memory by the
|
||||
* earlier call to intel_uc_init_fw(), so here we need to only check that
|
||||
* fetch succeeded, and then transfer the image to the h/w.
|
||||
*
|
||||
* Return: non-zero code on error
|
||||
*/
|
||||
int intel_huc_fw_upload(struct intel_huc *huc)
|
||||
{
|
||||
return intel_uc_fw_upload(&huc->fw, huc_fw_xfer);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright © 2014-2018 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_HUC_FW_H_
|
||||
#define _INTEL_HUC_FW_H_
|
||||
|
||||
struct intel_huc;
|
||||
|
||||
void intel_huc_fw_init_early(struct intel_huc *huc);
|
||||
int intel_huc_fw_upload(struct intel_huc *huc);
|
||||
|
||||
#endif
|
|
@ -169,6 +169,23 @@ static void execlists_init_reg_state(u32 *reg_state,
|
|||
struct intel_engine_cs *engine,
|
||||
struct intel_ring *ring);
|
||||
|
||||
static inline struct i915_priolist *to_priolist(struct rb_node *rb)
|
||||
{
|
||||
return rb_entry(rb, struct i915_priolist, node);
|
||||
}
|
||||
|
||||
static inline int rq_prio(const struct i915_request *rq)
|
||||
{
|
||||
return rq->priotree.priority;
|
||||
}
|
||||
|
||||
static inline bool need_preempt(const struct intel_engine_cs *engine,
|
||||
const struct i915_request *last,
|
||||
int prio)
|
||||
{
|
||||
return engine->i915->preempt_context && prio > max(rq_prio(last), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_lr_context_descriptor_update() - calculate & cache the descriptor
|
||||
* descriptor for a pinned context
|
||||
|
@ -187,6 +204,18 @@ static void execlists_init_reg_state(u32 *reg_state,
|
|||
* bits 32-52: ctx ID, a globally unique tag
|
||||
* bits 53-54: mbz, reserved for use by hardware
|
||||
* bits 55-63: group ID, currently unused and set to 0
|
||||
*
|
||||
* Starting from Gen11, the upper dword of the descriptor has a new format:
|
||||
*
|
||||
* bits 32-36: reserved
|
||||
* bits 37-47: SW context ID
|
||||
* bits 48:53: engine instance
|
||||
* bit 54: mbz, reserved for use by hardware
|
||||
* bits 55-60: SW counter
|
||||
* bits 61-63: engine class
|
||||
*
|
||||
* engine info, SW context ID and SW counter need to form a unique number
|
||||
* (Context ID) per lrc.
|
||||
*/
|
||||
static void
|
||||
intel_lr_context_descriptor_update(struct i915_gem_context *ctx,
|
||||
|
@ -195,12 +224,32 @@ intel_lr_context_descriptor_update(struct i915_gem_context *ctx,
|
|||
struct intel_context *ce = &ctx->engine[engine->id];
|
||||
u64 desc;
|
||||
|
||||
BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (1<<GEN8_CTX_ID_WIDTH));
|
||||
BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (BIT(GEN8_CTX_ID_WIDTH)));
|
||||
BUILD_BUG_ON(GEN11_MAX_CONTEXT_HW_ID > (BIT(GEN11_SW_CTX_ID_WIDTH)));
|
||||
|
||||
desc = ctx->desc_template; /* bits 0-11 */
|
||||
GEM_BUG_ON(desc & GENMASK_ULL(63, 12));
|
||||
|
||||
desc |= i915_ggtt_offset(ce->state) + LRC_HEADER_PAGES * PAGE_SIZE;
|
||||
/* bits 12-31 */
|
||||
desc |= (u64)ctx->hw_id << GEN8_CTX_ID_SHIFT; /* bits 32-52 */
|
||||
GEM_BUG_ON(desc & GENMASK_ULL(63, 32));
|
||||
|
||||
if (INTEL_GEN(ctx->i915) >= 11) {
|
||||
GEM_BUG_ON(ctx->hw_id >= BIT(GEN11_SW_CTX_ID_WIDTH));
|
||||
desc |= (u64)ctx->hw_id << GEN11_SW_CTX_ID_SHIFT;
|
||||
/* bits 37-47 */
|
||||
|
||||
desc |= (u64)engine->instance << GEN11_ENGINE_INSTANCE_SHIFT;
|
||||
/* bits 48-53 */
|
||||
|
||||
/* TODO: decide what to do with SW counter (bits 55-60) */
|
||||
|
||||
desc |= (u64)engine->class << GEN11_ENGINE_CLASS_SHIFT;
|
||||
/* bits 61-63 */
|
||||
} else {
|
||||
GEM_BUG_ON(ctx->hw_id >= BIT(GEN8_CTX_ID_WIDTH));
|
||||
desc |= (u64)ctx->hw_id << GEN8_CTX_ID_SHIFT; /* bits 32-52 */
|
||||
}
|
||||
|
||||
ce->lrc_desc = desc;
|
||||
}
|
||||
|
@ -224,7 +273,7 @@ lookup_priolist(struct intel_engine_cs *engine,
|
|||
parent = &execlists->queue.rb_node;
|
||||
while (*parent) {
|
||||
rb = *parent;
|
||||
p = rb_entry(rb, typeof(*p), node);
|
||||
p = to_priolist(rb);
|
||||
if (prio > p->priority) {
|
||||
parent = &rb->rb_left;
|
||||
} else if (prio < p->priority) {
|
||||
|
@ -264,10 +313,10 @@ lookup_priolist(struct intel_engine_cs *engine,
|
|||
if (first)
|
||||
execlists->first = &p->node;
|
||||
|
||||
return ptr_pack_bits(p, first, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void unwind_wa_tail(struct drm_i915_gem_request *rq)
|
||||
static void unwind_wa_tail(struct i915_request *rq)
|
||||
{
|
||||
rq->tail = intel_ring_wrap(rq->ring, rq->wa_tail - WA_TAIL_BYTES);
|
||||
assert_ring_tail_valid(rq->ring, rq->tail);
|
||||
|
@ -275,7 +324,7 @@ static void unwind_wa_tail(struct drm_i915_gem_request *rq)
|
|||
|
||||
static void __unwind_incomplete_requests(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *rq, *rn;
|
||||
struct i915_request *rq, *rn;
|
||||
struct i915_priolist *uninitialized_var(p);
|
||||
int last_prio = I915_PRIORITY_INVALID;
|
||||
|
||||
|
@ -284,20 +333,16 @@ static void __unwind_incomplete_requests(struct intel_engine_cs *engine)
|
|||
list_for_each_entry_safe_reverse(rq, rn,
|
||||
&engine->timeline->requests,
|
||||
link) {
|
||||
if (i915_gem_request_completed(rq))
|
||||
if (i915_request_completed(rq))
|
||||
return;
|
||||
|
||||
__i915_gem_request_unsubmit(rq);
|
||||
__i915_request_unsubmit(rq);
|
||||
unwind_wa_tail(rq);
|
||||
|
||||
GEM_BUG_ON(rq->priotree.priority == I915_PRIORITY_INVALID);
|
||||
if (rq->priotree.priority != last_prio) {
|
||||
p = lookup_priolist(engine,
|
||||
&rq->priotree,
|
||||
rq->priotree.priority);
|
||||
p = ptr_mask_bits(p, 1);
|
||||
|
||||
last_prio = rq->priotree.priority;
|
||||
GEM_BUG_ON(rq_prio(rq) == I915_PRIORITY_INVALID);
|
||||
if (rq_prio(rq) != last_prio) {
|
||||
last_prio = rq_prio(rq);
|
||||
p = lookup_priolist(engine, &rq->priotree, last_prio);
|
||||
}
|
||||
|
||||
list_add(&rq->priotree.link, &p->requests);
|
||||
|
@ -316,8 +361,7 @@ execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists)
|
|||
}
|
||||
|
||||
static inline void
|
||||
execlists_context_status_change(struct drm_i915_gem_request *rq,
|
||||
unsigned long status)
|
||||
execlists_context_status_change(struct i915_request *rq, unsigned long status)
|
||||
{
|
||||
/*
|
||||
* Only used when GVT-g is enabled now. When GVT-g is disabled,
|
||||
|
@ -331,14 +375,14 @@ execlists_context_status_change(struct drm_i915_gem_request *rq,
|
|||
}
|
||||
|
||||
static inline void
|
||||
execlists_context_schedule_in(struct drm_i915_gem_request *rq)
|
||||
execlists_context_schedule_in(struct i915_request *rq)
|
||||
{
|
||||
execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_IN);
|
||||
intel_engine_context_in(rq->engine);
|
||||
}
|
||||
|
||||
static inline void
|
||||
execlists_context_schedule_out(struct drm_i915_gem_request *rq)
|
||||
execlists_context_schedule_out(struct i915_request *rq)
|
||||
{
|
||||
intel_engine_context_out(rq->engine);
|
||||
execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT);
|
||||
|
@ -353,7 +397,7 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
|
|||
ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
|
||||
}
|
||||
|
||||
static u64 execlists_update_context(struct drm_i915_gem_request *rq)
|
||||
static u64 execlists_update_context(struct i915_request *rq)
|
||||
{
|
||||
struct intel_context *ce = &rq->ctx->engine[rq->engine->id];
|
||||
struct i915_hw_ppgtt *ppgtt =
|
||||
|
@ -373,19 +417,31 @@ static u64 execlists_update_context(struct drm_i915_gem_request *rq)
|
|||
return ce->lrc_desc;
|
||||
}
|
||||
|
||||
static inline void elsp_write(u64 desc, u32 __iomem *elsp)
|
||||
static inline void write_desc(struct intel_engine_execlists *execlists, u64 desc, u32 port)
|
||||
{
|
||||
writel(upper_32_bits(desc), elsp);
|
||||
writel(lower_32_bits(desc), elsp);
|
||||
if (execlists->ctrl_reg) {
|
||||
writel(lower_32_bits(desc), execlists->submit_reg + port * 2);
|
||||
writel(upper_32_bits(desc), execlists->submit_reg + port * 2 + 1);
|
||||
} else {
|
||||
writel(upper_32_bits(desc), execlists->submit_reg);
|
||||
writel(lower_32_bits(desc), execlists->submit_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void execlists_submit_ports(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct execlist_port *port = engine->execlists.port;
|
||||
struct intel_engine_execlists *execlists = &engine->execlists;
|
||||
struct execlist_port *port = execlists->port;
|
||||
unsigned int n;
|
||||
|
||||
for (n = execlists_num_ports(&engine->execlists); n--; ) {
|
||||
struct drm_i915_gem_request *rq;
|
||||
/*
|
||||
* ELSQ note: the submit queue is not cleared after being submitted
|
||||
* to the HW so we need to make sure we always clean it up. This is
|
||||
* currently ensured by the fact that we always write the same number
|
||||
* of elsq entries, keep this in mind before changing the loop below.
|
||||
*/
|
||||
for (n = execlists_num_ports(execlists); n--; ) {
|
||||
struct i915_request *rq;
|
||||
unsigned int count;
|
||||
u64 desc;
|
||||
|
||||
|
@ -398,18 +454,24 @@ static void execlists_submit_ports(struct intel_engine_cs *engine)
|
|||
desc = execlists_update_context(rq);
|
||||
GEM_DEBUG_EXEC(port[n].context_id = upper_32_bits(desc));
|
||||
|
||||
GEM_TRACE("%s in[%d]: ctx=%d.%d, seqno=%x\n",
|
||||
GEM_TRACE("%s in[%d]: ctx=%d.%d, seqno=%x, prio=%d\n",
|
||||
engine->name, n,
|
||||
port[n].context_id, count,
|
||||
rq->global_seqno);
|
||||
rq->global_seqno,
|
||||
rq_prio(rq));
|
||||
} else {
|
||||
GEM_BUG_ON(!n);
|
||||
desc = 0;
|
||||
}
|
||||
|
||||
elsp_write(desc, engine->execlists.elsp);
|
||||
write_desc(execlists, desc, n);
|
||||
}
|
||||
execlists_clear_active(&engine->execlists, EXECLISTS_ACTIVE_HWACK);
|
||||
|
||||
/* we need to manually load the submit queue */
|
||||
if (execlists->ctrl_reg)
|
||||
writel(EL_CTRL_LOAD, execlists->ctrl_reg);
|
||||
|
||||
execlists_clear_active(execlists, EXECLISTS_ACTIVE_HWACK);
|
||||
}
|
||||
|
||||
static bool ctx_single_port_submission(const struct i915_gem_context *ctx)
|
||||
|
@ -430,44 +492,47 @@ static bool can_merge_ctx(const struct i915_gem_context *prev,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void port_assign(struct execlist_port *port,
|
||||
struct drm_i915_gem_request *rq)
|
||||
static void port_assign(struct execlist_port *port, struct i915_request *rq)
|
||||
{
|
||||
GEM_BUG_ON(rq == port_request(port));
|
||||
|
||||
if (port_isset(port))
|
||||
i915_gem_request_put(port_request(port));
|
||||
i915_request_put(port_request(port));
|
||||
|
||||
port_set(port, port_pack(i915_gem_request_get(rq), port_count(port)));
|
||||
port_set(port, port_pack(i915_request_get(rq), port_count(port)));
|
||||
}
|
||||
|
||||
static void inject_preempt_context(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct intel_engine_execlists *execlists = &engine->execlists;
|
||||
struct intel_context *ce =
|
||||
&engine->i915->preempt_context->engine[engine->id];
|
||||
unsigned int n;
|
||||
|
||||
GEM_BUG_ON(engine->execlists.preempt_complete_status !=
|
||||
GEM_BUG_ON(execlists->preempt_complete_status !=
|
||||
upper_32_bits(ce->lrc_desc));
|
||||
GEM_BUG_ON(!IS_ALIGNED(ce->ring->size, WA_TAIL_BYTES));
|
||||
|
||||
memset(ce->ring->vaddr + ce->ring->tail, 0, WA_TAIL_BYTES);
|
||||
ce->ring->tail += WA_TAIL_BYTES;
|
||||
ce->ring->tail &= (ce->ring->size - 1);
|
||||
ce->lrc_reg_state[CTX_RING_TAIL+1] = ce->ring->tail;
|
||||
|
||||
GEM_BUG_ON((ce->lrc_reg_state[CTX_CONTEXT_CONTROL + 1] &
|
||||
_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
|
||||
CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT)) !=
|
||||
_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
|
||||
CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT));
|
||||
|
||||
/*
|
||||
* Switch to our empty preempt context so
|
||||
* the state of the GPU is known (idle).
|
||||
*/
|
||||
GEM_TRACE("%s\n", engine->name);
|
||||
for (n = execlists_num_ports(&engine->execlists); --n; )
|
||||
elsp_write(0, engine->execlists.elsp);
|
||||
for (n = execlists_num_ports(execlists); --n; )
|
||||
write_desc(execlists, 0, n);
|
||||
|
||||
write_desc(execlists, ce->lrc_desc, n);
|
||||
|
||||
/* we need to manually load the submit queue */
|
||||
if (execlists->ctrl_reg)
|
||||
writel(EL_CTRL_LOAD, execlists->ctrl_reg);
|
||||
|
||||
elsp_write(ce->lrc_desc, engine->execlists.elsp);
|
||||
execlists_clear_active(&engine->execlists, EXECLISTS_ACTIVE_HWACK);
|
||||
execlists_set_active(&engine->execlists, EXECLISTS_ACTIVE_PREEMPT);
|
||||
}
|
||||
|
||||
static void execlists_dequeue(struct intel_engine_cs *engine)
|
||||
|
@ -476,7 +541,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|||
struct execlist_port *port = execlists->port;
|
||||
const struct execlist_port * const last_port =
|
||||
&execlists->port[execlists->port_mask];
|
||||
struct drm_i915_gem_request *last = port_request(port);
|
||||
struct i915_request *last = port_request(port);
|
||||
struct rb_node *rb;
|
||||
bool submit = false;
|
||||
|
||||
|
@ -504,8 +569,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|||
spin_lock_irq(&engine->timeline->lock);
|
||||
rb = execlists->first;
|
||||
GEM_BUG_ON(rb_first(&execlists->queue) != rb);
|
||||
if (!rb)
|
||||
goto unlock;
|
||||
|
||||
if (last) {
|
||||
/*
|
||||
|
@ -528,55 +591,49 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|||
if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_HWACK))
|
||||
goto unlock;
|
||||
|
||||
if (engine->i915->preempt_context &&
|
||||
rb_entry(rb, struct i915_priolist, node)->priority >
|
||||
max(last->priotree.priority, 0)) {
|
||||
/*
|
||||
* Switch to our empty preempt context so
|
||||
* the state of the GPU is known (idle).
|
||||
*/
|
||||
if (need_preempt(engine, last, execlists->queue_priority)) {
|
||||
inject_preempt_context(engine);
|
||||
execlists_set_active(execlists,
|
||||
EXECLISTS_ACTIVE_PREEMPT);
|
||||
goto unlock;
|
||||
} else {
|
||||
/*
|
||||
* In theory, we could coalesce more requests onto
|
||||
* the second port (the first port is active, with
|
||||
* no preemptions pending). However, that means we
|
||||
* then have to deal with the possible lite-restore
|
||||
* of the second port (as we submit the ELSP, there
|
||||
* may be a context-switch) but also we may complete
|
||||
* the resubmission before the context-switch. Ergo,
|
||||
* coalescing onto the second port will cause a
|
||||
* preemption event, but we cannot predict whether
|
||||
* that will affect port[0] or port[1].
|
||||
*
|
||||
* If the second port is already active, we can wait
|
||||
* until the next context-switch before contemplating
|
||||
* new requests. The GPU will be busy and we should be
|
||||
* able to resubmit the new ELSP before it idles,
|
||||
* avoiding pipeline bubbles (momentary pauses where
|
||||
* the driver is unable to keep up the supply of new
|
||||
* work).
|
||||
*/
|
||||
if (port_count(&port[1]))
|
||||
goto unlock;
|
||||
|
||||
/* WaIdleLiteRestore:bdw,skl
|
||||
* Apply the wa NOOPs to prevent
|
||||
* ring:HEAD == req:TAIL as we resubmit the
|
||||
* request. See gen8_emit_breadcrumb() for
|
||||
* where we prepare the padding after the
|
||||
* end of the request.
|
||||
*/
|
||||
last->tail = last->wa_tail;
|
||||
}
|
||||
|
||||
/*
|
||||
* In theory, we could coalesce more requests onto
|
||||
* the second port (the first port is active, with
|
||||
* no preemptions pending). However, that means we
|
||||
* then have to deal with the possible lite-restore
|
||||
* of the second port (as we submit the ELSP, there
|
||||
* may be a context-switch) but also we may complete
|
||||
* the resubmission before the context-switch. Ergo,
|
||||
* coalescing onto the second port will cause a
|
||||
* preemption event, but we cannot predict whether
|
||||
* that will affect port[0] or port[1].
|
||||
*
|
||||
* If the second port is already active, we can wait
|
||||
* until the next context-switch before contemplating
|
||||
* new requests. The GPU will be busy and we should be
|
||||
* able to resubmit the new ELSP before it idles,
|
||||
* avoiding pipeline bubbles (momentary pauses where
|
||||
* the driver is unable to keep up the supply of new
|
||||
* work). However, we have to double check that the
|
||||
* priorities of the ports haven't been switch.
|
||||
*/
|
||||
if (port_count(&port[1]))
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* WaIdleLiteRestore:bdw,skl
|
||||
* Apply the wa NOOPs to prevent
|
||||
* ring:HEAD == rq:TAIL as we resubmit the
|
||||
* request. See gen8_emit_breadcrumb() for
|
||||
* where we prepare the padding after the
|
||||
* end of the request.
|
||||
*/
|
||||
last->tail = last->wa_tail;
|
||||
}
|
||||
|
||||
do {
|
||||
struct i915_priolist *p = rb_entry(rb, typeof(*p), node);
|
||||
struct drm_i915_gem_request *rq, *rn;
|
||||
while (rb) {
|
||||
struct i915_priolist *p = to_priolist(rb);
|
||||
struct i915_request *rq, *rn;
|
||||
|
||||
list_for_each_entry_safe(rq, rn, &p->requests, priotree.link) {
|
||||
/*
|
||||
|
@ -626,8 +683,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|||
}
|
||||
|
||||
INIT_LIST_HEAD(&rq->priotree.link);
|
||||
__i915_gem_request_submit(rq);
|
||||
trace_i915_gem_request_in(rq, port_index(port, execlists));
|
||||
__i915_request_submit(rq);
|
||||
trace_i915_request_in(rq, port_index(port, execlists));
|
||||
last = rq;
|
||||
submit = true;
|
||||
}
|
||||
|
@ -637,8 +694,9 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|||
INIT_LIST_HEAD(&p->requests);
|
||||
if (p->priority != I915_PRIORITY_NORMAL)
|
||||
kmem_cache_free(engine->i915->priorities, p);
|
||||
} while (rb);
|
||||
}
|
||||
done:
|
||||
execlists->queue_priority = rb ? to_priolist(rb)->priority : INT_MIN;
|
||||
execlists->first = rb;
|
||||
if (submit)
|
||||
port_assign(port, last);
|
||||
|
@ -665,12 +723,17 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists)
|
|||
unsigned int num_ports = execlists_num_ports(execlists);
|
||||
|
||||
while (num_ports-- && port_isset(port)) {
|
||||
struct drm_i915_gem_request *rq = port_request(port);
|
||||
struct i915_request *rq = port_request(port);
|
||||
|
||||
GEM_BUG_ON(!execlists->active);
|
||||
intel_engine_context_out(rq->engine);
|
||||
execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_PREEMPTED);
|
||||
i915_gem_request_put(rq);
|
||||
|
||||
execlists_context_status_change(rq,
|
||||
i915_request_completed(rq) ?
|
||||
INTEL_CONTEXT_SCHEDULE_OUT :
|
||||
INTEL_CONTEXT_SCHEDULE_PREEMPTED);
|
||||
|
||||
i915_request_put(rq);
|
||||
|
||||
memset(port, 0, sizeof(*port));
|
||||
port++;
|
||||
|
@ -680,32 +743,50 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists)
|
|||
static void execlists_cancel_requests(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct intel_engine_execlists * const execlists = &engine->execlists;
|
||||
struct drm_i915_gem_request *rq, *rn;
|
||||
struct i915_request *rq, *rn;
|
||||
struct rb_node *rb;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&engine->timeline->lock, flags);
|
||||
GEM_TRACE("%s\n", engine->name);
|
||||
|
||||
/*
|
||||
* Before we call engine->cancel_requests(), we should have exclusive
|
||||
* access to the submission state. This is arranged for us by the
|
||||
* caller disabling the interrupt generation, the tasklet and other
|
||||
* threads that may then access the same state, giving us a free hand
|
||||
* to reset state. However, we still need to let lockdep be aware that
|
||||
* we know this state may be accessed in hardirq context, so we
|
||||
* disable the irq around this manipulation and we want to keep
|
||||
* the spinlock focused on its duties and not accidentally conflate
|
||||
* coverage to the submission's irq state. (Similarly, although we
|
||||
* shouldn't need to disable irq around the manipulation of the
|
||||
* submission's irq state, we also wish to remind ourselves that
|
||||
* it is irq state.)
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
/* Cancel the requests on the HW and clear the ELSP tracker. */
|
||||
execlists_cancel_port_requests(execlists);
|
||||
|
||||
spin_lock(&engine->timeline->lock);
|
||||
|
||||
/* Mark all executing requests as skipped. */
|
||||
list_for_each_entry(rq, &engine->timeline->requests, link) {
|
||||
GEM_BUG_ON(!rq->global_seqno);
|
||||
if (!i915_gem_request_completed(rq))
|
||||
if (!i915_request_completed(rq))
|
||||
dma_fence_set_error(&rq->fence, -EIO);
|
||||
}
|
||||
|
||||
/* Flush the queued requests to the timeline list (for retiring). */
|
||||
rb = execlists->first;
|
||||
while (rb) {
|
||||
struct i915_priolist *p = rb_entry(rb, typeof(*p), node);
|
||||
struct i915_priolist *p = to_priolist(rb);
|
||||
|
||||
list_for_each_entry_safe(rq, rn, &p->requests, priotree.link) {
|
||||
INIT_LIST_HEAD(&rq->priotree.link);
|
||||
|
||||
dma_fence_set_error(&rq->fence, -EIO);
|
||||
__i915_gem_request_submit(rq);
|
||||
__i915_request_submit(rq);
|
||||
}
|
||||
|
||||
rb = rb_next(rb);
|
||||
|
@ -717,11 +798,13 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
|
|||
|
||||
/* Remaining _unready_ requests will be nop'ed when submitted */
|
||||
|
||||
|
||||
execlists->queue_priority = INT_MIN;
|
||||
execlists->queue = RB_ROOT;
|
||||
execlists->first = NULL;
|
||||
GEM_BUG_ON(port_isset(execlists->port));
|
||||
|
||||
spin_unlock(&engine->timeline->lock);
|
||||
|
||||
/*
|
||||
* The port is checked prior to scheduling a tasklet, but
|
||||
* just in case we have suspended the tasklet to do the
|
||||
|
@ -730,7 +813,10 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
|
|||
*/
|
||||
clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
|
||||
|
||||
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
||||
/* Mark all CS interrupts as complete */
|
||||
execlists->active = 0;
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -806,7 +892,7 @@ static void execlists_submission_tasklet(unsigned long data)
|
|||
tail, GEN8_CSB_WRITE_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?");
|
||||
|
||||
while (head != tail) {
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
unsigned int status;
|
||||
unsigned int count;
|
||||
|
||||
|
@ -872,23 +958,28 @@ static void execlists_submission_tasklet(unsigned long data)
|
|||
GEM_BUG_ON(!execlists_is_active(execlists,
|
||||
EXECLISTS_ACTIVE_USER));
|
||||
|
||||
rq = port_unpack(port, &count);
|
||||
GEM_TRACE("%s out[0]: ctx=%d.%d, seqno=%x, prio=%d\n",
|
||||
engine->name,
|
||||
port->context_id, count,
|
||||
rq ? rq->global_seqno : 0,
|
||||
rq ? rq_prio(rq) : 0);
|
||||
|
||||
/* Check the context/desc id for this event matches */
|
||||
GEM_DEBUG_BUG_ON(buf[2 * head + 1] != port->context_id);
|
||||
|
||||
rq = port_unpack(port, &count);
|
||||
GEM_TRACE("%s out[0]: ctx=%d.%d, seqno=%x\n",
|
||||
engine->name,
|
||||
port->context_id, count,
|
||||
rq ? rq->global_seqno : 0);
|
||||
GEM_BUG_ON(count == 0);
|
||||
if (--count == 0) {
|
||||
GEM_BUG_ON(status & GEN8_CTX_STATUS_PREEMPTED);
|
||||
GEM_BUG_ON(port_isset(&port[1]) &&
|
||||
!(status & GEN8_CTX_STATUS_ELEMENT_SWITCH));
|
||||
GEM_BUG_ON(!i915_gem_request_completed(rq));
|
||||
GEM_BUG_ON(!i915_request_completed(rq));
|
||||
execlists_context_schedule_out(rq);
|
||||
trace_i915_gem_request_out(rq);
|
||||
i915_gem_request_put(rq);
|
||||
trace_i915_request_out(rq);
|
||||
i915_request_put(rq);
|
||||
|
||||
GEM_TRACE("%s completed ctx=%d\n",
|
||||
engine->name, port->context_id);
|
||||
|
||||
execlists_port_complete(execlists, port);
|
||||
} else {
|
||||
|
@ -917,18 +1008,22 @@ static void execlists_submission_tasklet(unsigned long data)
|
|||
intel_uncore_forcewake_put(dev_priv, execlists->fw_domains);
|
||||
}
|
||||
|
||||
static void insert_request(struct intel_engine_cs *engine,
|
||||
struct i915_priotree *pt,
|
||||
int prio)
|
||||
static void queue_request(struct intel_engine_cs *engine,
|
||||
struct i915_priotree *pt,
|
||||
int prio)
|
||||
{
|
||||
struct i915_priolist *p = lookup_priolist(engine, pt, prio);
|
||||
|
||||
list_add_tail(&pt->link, &ptr_mask_bits(p, 1)->requests);
|
||||
if (ptr_unmask_bits(p, 1))
|
||||
tasklet_hi_schedule(&engine->execlists.tasklet);
|
||||
list_add_tail(&pt->link, &lookup_priolist(engine, pt, prio)->requests);
|
||||
}
|
||||
|
||||
static void execlists_submit_request(struct drm_i915_gem_request *request)
|
||||
static void submit_queue(struct intel_engine_cs *engine, int prio)
|
||||
{
|
||||
if (prio > engine->execlists.queue_priority) {
|
||||
engine->execlists.queue_priority = prio;
|
||||
tasklet_hi_schedule(&engine->execlists.tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
static void execlists_submit_request(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
unsigned long flags;
|
||||
|
@ -936,7 +1031,8 @@ static void execlists_submit_request(struct drm_i915_gem_request *request)
|
|||
/* Will be called from irq-context when using foreign fences. */
|
||||
spin_lock_irqsave(&engine->timeline->lock, flags);
|
||||
|
||||
insert_request(engine, &request->priotree, request->priotree.priority);
|
||||
queue_request(engine, &request->priotree, rq_prio(request));
|
||||
submit_queue(engine, rq_prio(request));
|
||||
|
||||
GEM_BUG_ON(!engine->execlists.first);
|
||||
GEM_BUG_ON(list_empty(&request->priotree.link));
|
||||
|
@ -944,9 +1040,9 @@ static void execlists_submit_request(struct drm_i915_gem_request *request)
|
|||
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
||||
}
|
||||
|
||||
static struct drm_i915_gem_request *pt_to_request(struct i915_priotree *pt)
|
||||
static struct i915_request *pt_to_request(struct i915_priotree *pt)
|
||||
{
|
||||
return container_of(pt, struct drm_i915_gem_request, priotree);
|
||||
return container_of(pt, struct i915_request, priotree);
|
||||
}
|
||||
|
||||
static struct intel_engine_cs *
|
||||
|
@ -964,7 +1060,7 @@ pt_lock_engine(struct i915_priotree *pt, struct intel_engine_cs *locked)
|
|||
return engine;
|
||||
}
|
||||
|
||||
static void execlists_schedule(struct drm_i915_gem_request *request, int prio)
|
||||
static void execlists_schedule(struct i915_request *request, int prio)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
struct i915_dependency *dep, *p;
|
||||
|
@ -973,7 +1069,7 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio)
|
|||
|
||||
GEM_BUG_ON(prio == I915_PRIORITY_INVALID);
|
||||
|
||||
if (i915_gem_request_completed(request))
|
||||
if (i915_request_completed(request))
|
||||
return;
|
||||
|
||||
if (prio <= READ_ONCE(request->priotree.priority))
|
||||
|
@ -992,7 +1088,7 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio)
|
|||
* static void update_priorities(struct i915_priotree *pt, prio) {
|
||||
* list_for_each_entry(dep, &pt->signalers_list, signal_link)
|
||||
* update_priorities(dep->signal, prio)
|
||||
* insert_request(pt);
|
||||
* queue_request(pt);
|
||||
* }
|
||||
* but that may have unlimited recursion depth and so runs a very
|
||||
* real risk of overunning the kernel stack. Instead, we build
|
||||
|
@ -1055,8 +1151,9 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio)
|
|||
pt->priority = prio;
|
||||
if (!list_empty(&pt->link)) {
|
||||
__list_del_entry(&pt->link);
|
||||
insert_request(engine, pt, prio);
|
||||
queue_request(engine, pt, prio);
|
||||
}
|
||||
submit_queue(engine, prio);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&engine->timeline->lock);
|
||||
|
@ -1158,7 +1255,7 @@ static void execlists_context_unpin(struct intel_engine_cs *engine,
|
|||
i915_gem_context_put(ctx);
|
||||
}
|
||||
|
||||
static int execlists_request_alloc(struct drm_i915_gem_request *request)
|
||||
static int execlists_request_alloc(struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_context *ce = &request->ctx->engine[engine->id];
|
||||
|
@ -1590,7 +1687,7 @@ static void reset_irq(struct intel_engine_cs *engine)
|
|||
}
|
||||
|
||||
static void reset_common_ring(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request)
|
||||
struct i915_request *request)
|
||||
{
|
||||
struct intel_engine_execlists * const execlists = &engine->execlists;
|
||||
struct intel_context *ce;
|
||||
|
@ -1599,9 +1696,10 @@ static void reset_common_ring(struct intel_engine_cs *engine,
|
|||
GEM_TRACE("%s seqno=%x\n",
|
||||
engine->name, request ? request->global_seqno : 0);
|
||||
|
||||
reset_irq(engine);
|
||||
/* See execlists_cancel_requests() for the irq/spinlock split. */
|
||||
local_irq_save(flags);
|
||||
|
||||
spin_lock_irqsave(&engine->timeline->lock, flags);
|
||||
reset_irq(engine);
|
||||
|
||||
/*
|
||||
* Catch up with any missed context-switch interrupts.
|
||||
|
@ -1615,14 +1713,17 @@ static void reset_common_ring(struct intel_engine_cs *engine,
|
|||
execlists_cancel_port_requests(execlists);
|
||||
|
||||
/* Push back any incomplete requests for replay after the reset. */
|
||||
spin_lock(&engine->timeline->lock);
|
||||
__unwind_incomplete_requests(engine);
|
||||
|
||||
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
||||
spin_unlock(&engine->timeline->lock);
|
||||
|
||||
/* Mark all CS interrupts as complete */
|
||||
execlists->active = 0;
|
||||
|
||||
/* If the request was innocent, we leave the request in the ELSP
|
||||
local_irq_restore(flags);
|
||||
|
||||
/*
|
||||
* If the request was innocent, we leave the request in the ELSP
|
||||
* and will try to replay it on restarting. The context image may
|
||||
* have been corrupted by the reset, in which case we may have
|
||||
* to service a new GPU hang, but more likely we can continue on
|
||||
|
@ -1635,7 +1736,8 @@ static void reset_common_ring(struct intel_engine_cs *engine,
|
|||
if (!request || request->fence.error != -EIO)
|
||||
return;
|
||||
|
||||
/* We want a simple context + ring to execute the breadcrumb update.
|
||||
/*
|
||||
* We want a simple context + ring to execute the breadcrumb update.
|
||||
* We cannot rely on the context being intact across the GPU hang,
|
||||
* so clear it and rebuild just what we need for the breadcrumb.
|
||||
* All pending requests for this context will be zapped, and any
|
||||
|
@ -1658,15 +1760,15 @@ static void reset_common_ring(struct intel_engine_cs *engine,
|
|||
unwind_wa_tail(request);
|
||||
}
|
||||
|
||||
static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req)
|
||||
static int intel_logical_ring_emit_pdps(struct i915_request *rq)
|
||||
{
|
||||
struct i915_hw_ppgtt *ppgtt = req->ctx->ppgtt;
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
const int num_lri_cmds = GEN8_3LVL_PDPES * 2;
|
||||
u32 *cs;
|
||||
int i;
|
||||
|
||||
cs = intel_ring_begin(req, num_lri_cmds * 2 + 2);
|
||||
cs = intel_ring_begin(rq, num_lri_cmds * 2 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1681,12 +1783,12 @@ static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req)
|
|||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen8_emit_bb_start(struct drm_i915_gem_request *req,
|
||||
static int gen8_emit_bb_start(struct i915_request *rq,
|
||||
u64 offset, u32 len,
|
||||
const unsigned int flags)
|
||||
{
|
||||
|
@ -1699,18 +1801,18 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req,
|
|||
* it is unsafe in case of lite-restore (because the ctx is
|
||||
* not idle). PML4 is allocated during ppgtt init so this is
|
||||
* not needed in 48-bit.*/
|
||||
if (req->ctx->ppgtt &&
|
||||
(intel_engine_flag(req->engine) & req->ctx->ppgtt->pd_dirty_rings) &&
|
||||
!i915_vm_is_48bit(&req->ctx->ppgtt->base) &&
|
||||
!intel_vgpu_active(req->i915)) {
|
||||
ret = intel_logical_ring_emit_pdps(req);
|
||||
if (rq->ctx->ppgtt &&
|
||||
(intel_engine_flag(rq->engine) & rq->ctx->ppgtt->pd_dirty_rings) &&
|
||||
!i915_vm_is_48bit(&rq->ctx->ppgtt->base) &&
|
||||
!intel_vgpu_active(rq->i915)) {
|
||||
ret = intel_logical_ring_emit_pdps(rq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
req->ctx->ppgtt->pd_dirty_rings &= ~intel_engine_flag(req->engine);
|
||||
rq->ctx->ppgtt->pd_dirty_rings &= ~intel_engine_flag(rq->engine);
|
||||
}
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1739,7 +1841,7 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req,
|
|||
(flags & I915_DISPATCH_RS ? MI_BATCH_RESOURCE_STREAMER : 0);
|
||||
*cs++ = lower_32_bits(offset);
|
||||
*cs++ = upper_32_bits(offset);
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1758,7 +1860,7 @@ static void gen8_logical_ring_disable_irq(struct intel_engine_cs *engine)
|
|||
I915_WRITE_IMR(engine, ~engine->irq_keep_mask);
|
||||
}
|
||||
|
||||
static int gen8_emit_flush(struct drm_i915_gem_request *request, u32 mode)
|
||||
static int gen8_emit_flush(struct i915_request *request, u32 mode)
|
||||
{
|
||||
u32 cmd, *cs;
|
||||
|
||||
|
@ -1790,7 +1892,7 @@ static int gen8_emit_flush(struct drm_i915_gem_request *request, u32 mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gen8_emit_flush_render(struct drm_i915_gem_request *request,
|
||||
static int gen8_emit_flush_render(struct i915_request *request,
|
||||
u32 mode)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
|
@ -1865,7 +1967,7 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request,
|
|||
* used as a workaround for not being allowed to do lite
|
||||
* restore with HEAD==TAIL (WaIdleLiteRestore).
|
||||
*/
|
||||
static void gen8_emit_wa_tail(struct drm_i915_gem_request *request, u32 *cs)
|
||||
static void gen8_emit_wa_tail(struct i915_request *request, u32 *cs)
|
||||
{
|
||||
/* Ensure there's always at least one preemption point per-request. */
|
||||
*cs++ = MI_ARB_CHECK;
|
||||
|
@ -1873,7 +1975,7 @@ static void gen8_emit_wa_tail(struct drm_i915_gem_request *request, u32 *cs)
|
|||
request->wa_tail = intel_ring_offset(request, cs);
|
||||
}
|
||||
|
||||
static void gen8_emit_breadcrumb(struct drm_i915_gem_request *request, u32 *cs)
|
||||
static void gen8_emit_breadcrumb(struct i915_request *request, u32 *cs)
|
||||
{
|
||||
/* w/a: bit 5 needs to be zero for MI_FLUSH_DW address. */
|
||||
BUILD_BUG_ON(I915_GEM_HWS_INDEX_ADDR & (1 << 5));
|
||||
|
@ -1889,8 +1991,7 @@ static void gen8_emit_breadcrumb(struct drm_i915_gem_request *request, u32 *cs)
|
|||
}
|
||||
static const int gen8_emit_breadcrumb_sz = 6 + WA_TAIL_DWORDS;
|
||||
|
||||
static void gen8_emit_breadcrumb_rcs(struct drm_i915_gem_request *request,
|
||||
u32 *cs)
|
||||
static void gen8_emit_breadcrumb_rcs(struct i915_request *request, u32 *cs)
|
||||
{
|
||||
/* We're using qword write, seqno should be aligned to 8 bytes. */
|
||||
BUILD_BUG_ON(I915_GEM_HWS_INDEX & 1);
|
||||
|
@ -1906,15 +2007,15 @@ static void gen8_emit_breadcrumb_rcs(struct drm_i915_gem_request *request,
|
|||
}
|
||||
static const int gen8_emit_breadcrumb_rcs_sz = 8 + WA_TAIL_DWORDS;
|
||||
|
||||
static int gen8_init_rcs_context(struct drm_i915_gem_request *req)
|
||||
static int gen8_init_rcs_context(struct i915_request *rq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = intel_ring_workarounds_emit(req);
|
||||
ret = intel_ring_workarounds_emit(rq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_rcs_context_init_mocs(req);
|
||||
ret = intel_rcs_context_init_mocs(rq);
|
||||
/*
|
||||
* Failing to program the MOCS is non-fatal.The system will not
|
||||
* run at peak performance. So generate an error and carry on.
|
||||
|
@ -1922,7 +2023,7 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req)
|
|||
if (ret)
|
||||
DRM_ERROR("MOCS failed to program: expect performance issues.\n");
|
||||
|
||||
return i915_gem_render_state_emit(req);
|
||||
return i915_gem_render_state_emit(rq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1996,8 +2097,17 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine)
|
|||
|
||||
engine->set_default_submission = execlists_set_default_submission;
|
||||
|
||||
engine->irq_enable = gen8_logical_ring_enable_irq;
|
||||
engine->irq_disable = gen8_logical_ring_disable_irq;
|
||||
if (INTEL_GEN(engine->i915) < 11) {
|
||||
engine->irq_enable = gen8_logical_ring_enable_irq;
|
||||
engine->irq_disable = gen8_logical_ring_disable_irq;
|
||||
} else {
|
||||
/*
|
||||
* TODO: On Gen11 interrupt masks need to be clear
|
||||
* to allow C6 entry. Keep interrupts enabled at
|
||||
* and take the hit of generating extra interrupts
|
||||
* until a more refined solution exists.
|
||||
*/
|
||||
}
|
||||
engine->emit_bb_start = gen8_emit_bb_start;
|
||||
}
|
||||
|
||||
|
@ -2049,8 +2159,15 @@ static int logical_ring_init(struct intel_engine_cs *engine)
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
engine->execlists.elsp =
|
||||
engine->i915->regs + i915_mmio_reg_offset(RING_ELSP(engine));
|
||||
if (HAS_LOGICAL_RING_ELSQ(engine->i915)) {
|
||||
engine->execlists.submit_reg = engine->i915->regs +
|
||||
i915_mmio_reg_offset(RING_EXECLIST_SQ_CONTENTS(engine));
|
||||
engine->execlists.ctrl_reg = engine->i915->regs +
|
||||
i915_mmio_reg_offset(RING_EXECLIST_CONTROL(engine));
|
||||
} else {
|
||||
engine->execlists.submit_reg = engine->i915->regs +
|
||||
i915_mmio_reg_offset(RING_ELSP(engine));
|
||||
}
|
||||
|
||||
engine->execlists.preempt_complete_status = ~0u;
|
||||
if (engine->i915->preempt_context)
|
||||
|
@ -2136,7 +2253,7 @@ make_rpcs(struct drm_i915_private *dev_priv)
|
|||
|
||||
if (INTEL_INFO(dev_priv)->sseu.has_subslice_pg) {
|
||||
rpcs |= GEN8_RPCS_SS_CNT_ENABLE;
|
||||
rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask) <<
|
||||
rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask[0]) <<
|
||||
GEN8_RPCS_SS_CNT_SHIFT;
|
||||
rpcs |= GEN8_RPCS_ENABLE;
|
||||
}
|
||||
|
@ -2160,6 +2277,10 @@ static u32 intel_lr_indirect_ctx_offset(struct intel_engine_cs *engine)
|
|||
default:
|
||||
MISSING_CASE(INTEL_GEN(engine->i915));
|
||||
/* fall through */
|
||||
case 11:
|
||||
indirect_ctx_offset =
|
||||
GEN11_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT;
|
||||
break;
|
||||
case 10:
|
||||
indirect_ctx_offset =
|
||||
GEN10_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT;
|
||||
|
@ -2319,7 +2440,7 @@ populate_lr_context(struct i915_gem_context *ctx,
|
|||
if (!engine->default_state)
|
||||
regs[CTX_CONTEXT_CONTROL + 1] |=
|
||||
_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
|
||||
if (ctx == ctx->i915->preempt_context)
|
||||
if (ctx == ctx->i915->preempt_context && INTEL_GEN(engine->i915) < 11)
|
||||
regs[CTX_CONTEXT_CONTROL + 1] |=
|
||||
_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
|
||||
CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT);
|
||||
|
|
|
@ -42,6 +42,9 @@
|
|||
#define RING_CONTEXT_STATUS_BUF_LO(engine, i) _MMIO((engine)->mmio_base + 0x370 + (i) * 8)
|
||||
#define RING_CONTEXT_STATUS_BUF_HI(engine, i) _MMIO((engine)->mmio_base + 0x370 + (i) * 8 + 4)
|
||||
#define RING_CONTEXT_STATUS_PTR(engine) _MMIO((engine)->mmio_base + 0x3a0)
|
||||
#define RING_EXECLIST_SQ_CONTENTS(engine) _MMIO((engine)->mmio_base + 0x510)
|
||||
#define RING_EXECLIST_CONTROL(engine) _MMIO((engine)->mmio_base + 0x550)
|
||||
#define EL_CTRL_LOAD (1 << 0)
|
||||
|
||||
/* The docs specify that the write pointer wraps around after 5h, "After status
|
||||
* is written out to the last available status QW at offset 5h, this pointer
|
||||
|
|
|
@ -63,5 +63,6 @@
|
|||
#define GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17
|
||||
#define GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x26
|
||||
#define GEN10_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x19
|
||||
#define GEN11_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x1A
|
||||
|
||||
#endif /* _INTEL_LRC_REG_H_ */
|
||||
|
|
|
@ -265,7 +265,7 @@ int intel_mocs_init_engine(struct intel_engine_cs *engine)
|
|||
|
||||
/**
|
||||
* emit_mocs_control_table() - emit the mocs control table
|
||||
* @req: Request to set up the MOCS table for.
|
||||
* @rq: Request to set up the MOCS table for.
|
||||
* @table: The values to program into the control regs.
|
||||
*
|
||||
* This function simply emits a MI_LOAD_REGISTER_IMM command for the
|
||||
|
@ -273,17 +273,17 @@ int intel_mocs_init_engine(struct intel_engine_cs *engine)
|
|||
*
|
||||
* Return: 0 on success, otherwise the error status.
|
||||
*/
|
||||
static int emit_mocs_control_table(struct drm_i915_gem_request *req,
|
||||
static int emit_mocs_control_table(struct i915_request *rq,
|
||||
const struct drm_i915_mocs_table *table)
|
||||
{
|
||||
enum intel_engine_id engine = req->engine->id;
|
||||
enum intel_engine_id engine = rq->engine->id;
|
||||
unsigned int index;
|
||||
u32 *cs;
|
||||
|
||||
if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES))
|
||||
return -ENODEV;
|
||||
|
||||
cs = intel_ring_begin(req, 2 + 2 * GEN9_NUM_MOCS_ENTRIES);
|
||||
cs = intel_ring_begin(rq, 2 + 2 * GEN9_NUM_MOCS_ENTRIES);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -308,7 +308,7 @@ static int emit_mocs_control_table(struct drm_i915_gem_request *req,
|
|||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ static inline u32 l3cc_combine(const struct drm_i915_mocs_table *table,
|
|||
|
||||
/**
|
||||
* emit_mocs_l3cc_table() - emit the mocs control table
|
||||
* @req: Request to set up the MOCS table for.
|
||||
* @rq: Request to set up the MOCS table for.
|
||||
* @table: The values to program into the control regs.
|
||||
*
|
||||
* This function simply emits a MI_LOAD_REGISTER_IMM command for the
|
||||
|
@ -332,7 +332,7 @@ static inline u32 l3cc_combine(const struct drm_i915_mocs_table *table,
|
|||
*
|
||||
* Return: 0 on success, otherwise the error status.
|
||||
*/
|
||||
static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
|
||||
static int emit_mocs_l3cc_table(struct i915_request *rq,
|
||||
const struct drm_i915_mocs_table *table)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -341,7 +341,7 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
|
|||
if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES))
|
||||
return -ENODEV;
|
||||
|
||||
cs = intel_ring_begin(req, 2 + GEN9_NUM_MOCS_ENTRIES);
|
||||
cs = intel_ring_begin(rq, 2 + GEN9_NUM_MOCS_ENTRIES);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -370,7 +370,7 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
|
|||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -417,7 +417,7 @@ void intel_mocs_init_l3cc_table(struct drm_i915_private *dev_priv)
|
|||
|
||||
/**
|
||||
* intel_rcs_context_init_mocs() - program the MOCS register.
|
||||
* @req: Request to set up the MOCS tables for.
|
||||
* @rq: Request to set up the MOCS tables for.
|
||||
*
|
||||
* This function will emit a batch buffer with the values required for
|
||||
* programming the MOCS register values for all the currently supported
|
||||
|
@ -431,19 +431,19 @@ void intel_mocs_init_l3cc_table(struct drm_i915_private *dev_priv)
|
|||
*
|
||||
* Return: 0 on success, otherwise the error status.
|
||||
*/
|
||||
int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req)
|
||||
int intel_rcs_context_init_mocs(struct i915_request *rq)
|
||||
{
|
||||
struct drm_i915_mocs_table t;
|
||||
int ret;
|
||||
|
||||
if (get_mocs_settings(req->i915, &t)) {
|
||||
if (get_mocs_settings(rq->i915, &t)) {
|
||||
/* Program the RCS control registers */
|
||||
ret = emit_mocs_control_table(req, &t);
|
||||
ret = emit_mocs_control_table(rq, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Now program the l3cc registers */
|
||||
ret = emit_mocs_l3cc_table(req, &t);
|
||||
ret = emit_mocs_l3cc_table(rq, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
#include <drm/drmP.h>
|
||||
#include "i915_drv.h"
|
||||
|
||||
int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req);
|
||||
int intel_rcs_context_init_mocs(struct i915_request *rq);
|
||||
void intel_mocs_init_l3cc_table(struct drm_i915_private *dev_priv);
|
||||
int intel_mocs_init_engine(struct intel_engine_cs *engine);
|
||||
|
||||
|
|
|
@ -234,50 +234,50 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
|
|||
}
|
||||
|
||||
static void intel_overlay_submit_request(struct intel_overlay *overlay,
|
||||
struct drm_i915_gem_request *req,
|
||||
struct i915_request *rq,
|
||||
i915_gem_retire_fn retire)
|
||||
{
|
||||
GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
|
||||
&overlay->i915->drm.struct_mutex));
|
||||
i915_gem_active_set_retire_fn(&overlay->last_flip, retire,
|
||||
&overlay->i915->drm.struct_mutex);
|
||||
i915_gem_active_set(&overlay->last_flip, req);
|
||||
i915_add_request(req);
|
||||
i915_gem_active_set(&overlay->last_flip, rq);
|
||||
i915_request_add(rq);
|
||||
}
|
||||
|
||||
static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
|
||||
struct drm_i915_gem_request *req,
|
||||
struct i915_request *rq,
|
||||
i915_gem_retire_fn retire)
|
||||
{
|
||||
intel_overlay_submit_request(overlay, req, retire);
|
||||
intel_overlay_submit_request(overlay, rq, retire);
|
||||
return i915_gem_active_retire(&overlay->last_flip,
|
||||
&overlay->i915->drm.struct_mutex);
|
||||
}
|
||||
|
||||
static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay)
|
||||
static struct i915_request *alloc_request(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = overlay->i915;
|
||||
struct intel_engine_cs *engine = dev_priv->engine[RCS];
|
||||
|
||||
return i915_gem_request_alloc(engine, dev_priv->kernel_context);
|
||||
return i915_request_alloc(engine, dev_priv->kernel_context);
|
||||
}
|
||||
|
||||
/* overlay needs to be disable in OCMD reg */
|
||||
static int intel_overlay_on(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = overlay->i915;
|
||||
struct drm_i915_gem_request *req;
|
||||
struct i915_request *rq;
|
||||
u32 *cs;
|
||||
|
||||
WARN_ON(overlay->active);
|
||||
|
||||
req = alloc_request(overlay);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
rq = alloc_request(overlay);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs)) {
|
||||
i915_add_request(req);
|
||||
i915_request_add(rq);
|
||||
return PTR_ERR(cs);
|
||||
}
|
||||
|
||||
|
@ -290,9 +290,9 @@ static int intel_overlay_on(struct intel_overlay *overlay)
|
|||
*cs++ = overlay->flip_addr | OFC_UPDATE;
|
||||
*cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return intel_overlay_do_wait_request(overlay, req, NULL);
|
||||
return intel_overlay_do_wait_request(overlay, rq, NULL);
|
||||
}
|
||||
|
||||
static void intel_overlay_flip_prepare(struct intel_overlay *overlay,
|
||||
|
@ -322,7 +322,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
|
|||
bool load_polyphase_filter)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = overlay->i915;
|
||||
struct drm_i915_gem_request *req;
|
||||
struct i915_request *rq;
|
||||
u32 flip_addr = overlay->flip_addr;
|
||||
u32 tmp, *cs;
|
||||
|
||||
|
@ -336,23 +336,23 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
|
|||
if (tmp & (1 << 17))
|
||||
DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
|
||||
|
||||
req = alloc_request(overlay);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
rq = alloc_request(overlay);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs)) {
|
||||
i915_add_request(req);
|
||||
i915_request_add(rq);
|
||||
return PTR_ERR(cs);
|
||||
}
|
||||
|
||||
*cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
|
||||
*cs++ = flip_addr;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
intel_overlay_flip_prepare(overlay, vma);
|
||||
|
||||
intel_overlay_submit_request(overlay, req, NULL);
|
||||
intel_overlay_submit_request(overlay, rq, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -373,7 +373,7 @@ static void intel_overlay_release_old_vma(struct intel_overlay *overlay)
|
|||
}
|
||||
|
||||
static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
|
||||
struct drm_i915_gem_request *req)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
struct intel_overlay *overlay =
|
||||
container_of(active, typeof(*overlay), last_flip);
|
||||
|
@ -382,7 +382,7 @@ static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
|
|||
}
|
||||
|
||||
static void intel_overlay_off_tail(struct i915_gem_active *active,
|
||||
struct drm_i915_gem_request *req)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
struct intel_overlay *overlay =
|
||||
container_of(active, typeof(*overlay), last_flip);
|
||||
|
@ -401,7 +401,7 @@ static void intel_overlay_off_tail(struct i915_gem_active *active,
|
|||
/* overlay needs to be disabled in OCMD reg */
|
||||
static int intel_overlay_off(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_i915_gem_request *req;
|
||||
struct i915_request *rq;
|
||||
u32 *cs, flip_addr = overlay->flip_addr;
|
||||
|
||||
WARN_ON(!overlay->active);
|
||||
|
@ -412,13 +412,13 @@ static int intel_overlay_off(struct intel_overlay *overlay)
|
|||
* of the hw. Do it in both cases */
|
||||
flip_addr |= OFC_UPDATE;
|
||||
|
||||
req = alloc_request(overlay);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
rq = alloc_request(overlay);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
cs = intel_ring_begin(req, 6);
|
||||
cs = intel_ring_begin(rq, 6);
|
||||
if (IS_ERR(cs)) {
|
||||
i915_add_request(req);
|
||||
i915_request_add(rq);
|
||||
return PTR_ERR(cs);
|
||||
}
|
||||
|
||||
|
@ -432,11 +432,11 @@ static int intel_overlay_off(struct intel_overlay *overlay)
|
|||
*cs++ = flip_addr;
|
||||
*cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
|
||||
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
intel_overlay_flip_prepare(overlay, NULL);
|
||||
|
||||
return intel_overlay_do_wait_request(overlay, req,
|
||||
return intel_overlay_do_wait_request(overlay, rq,
|
||||
intel_overlay_off_tail);
|
||||
}
|
||||
|
||||
|
@ -468,23 +468,23 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
|
|||
|
||||
if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
|
||||
/* synchronous slowpath */
|
||||
struct drm_i915_gem_request *req;
|
||||
struct i915_request *rq;
|
||||
|
||||
req = alloc_request(overlay);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
rq = alloc_request(overlay);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs)) {
|
||||
i915_add_request(req);
|
||||
i915_request_add(rq);
|
||||
return PTR_ERR(cs);
|
||||
}
|
||||
|
||||
*cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
ret = intel_overlay_do_wait_request(overlay, req,
|
||||
ret = intel_overlay_do_wait_request(overlay, rq,
|
||||
intel_overlay_release_old_vid_tail);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -6360,7 +6360,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
|
|||
mutex_unlock(&dev_priv->pcu_lock);
|
||||
}
|
||||
|
||||
void gen6_rps_boost(struct drm_i915_gem_request *rq,
|
||||
void gen6_rps_boost(struct i915_request *rq,
|
||||
struct intel_rps_client *rps_client)
|
||||
{
|
||||
struct intel_rps *rps = &rq->i915->gt_pm.rps;
|
||||
|
@ -6376,7 +6376,7 @@ void gen6_rps_boost(struct drm_i915_gem_request *rq,
|
|||
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
|
||||
return;
|
||||
|
||||
/* Serializes with i915_gem_request_retire() */
|
||||
/* Serializes with i915_request_retire() */
|
||||
boost = false;
|
||||
spin_lock_irqsave(&rq->lock, flags);
|
||||
if (!rq->waitboost && !dma_fence_is_signaled_locked(&rq->fence)) {
|
||||
|
@ -6715,7 +6715,7 @@ static void gen9_enable_rc6(struct drm_i915_private *dev_priv)
|
|||
|
||||
/*
|
||||
* 3b: Enable Coarse Power Gating only when RC6 is enabled.
|
||||
* WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6.
|
||||
* WaRsDisableCoarsePowerGating:skl,cnl - Render/Media PG need to be disabled with RC6.
|
||||
*/
|
||||
if (NEEDS_WaRsDisableCoarsePowerGating(dev_priv))
|
||||
I915_WRITE(GEN9_PG_ENABLE, 0);
|
||||
|
@ -8026,7 +8026,10 @@ void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv)
|
|||
dev_priv->gt_pm.rc6.enabled = true; /* force RC6 disabling */
|
||||
intel_disable_gt_powersave(dev_priv);
|
||||
|
||||
gen6_reset_rps_interrupts(dev_priv);
|
||||
if (INTEL_GEN(dev_priv) < 11)
|
||||
gen6_reset_rps_interrupts(dev_priv);
|
||||
else
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
static inline void intel_disable_llc_pstate(struct drm_i915_private *i915)
|
||||
|
@ -8139,6 +8142,8 @@ static void intel_enable_rps(struct drm_i915_private *dev_priv)
|
|||
cherryview_enable_rps(dev_priv);
|
||||
} else if (IS_VALLEYVIEW(dev_priv)) {
|
||||
valleyview_enable_rps(dev_priv);
|
||||
} else if (WARN_ON_ONCE(INTEL_GEN(dev_priv) >= 11)) {
|
||||
/* TODO */
|
||||
} else if (INTEL_GEN(dev_priv) >= 9) {
|
||||
gen9_enable_rps(dev_priv);
|
||||
} else if (IS_BROADWELL(dev_priv)) {
|
||||
|
@ -8487,7 +8492,7 @@ static void cnp_init_clock_gating(struct drm_i915_private *dev_priv)
|
|||
if (!HAS_PCH_CNP(dev_priv))
|
||||
return;
|
||||
|
||||
/* Display WA #1181: cnp */
|
||||
/* Display WA #1181 WaSouthDisplayDisablePWMCGEGating: cnp */
|
||||
I915_WRITE(SOUTH_DSPCLK_GATE_D, I915_READ(SOUTH_DSPCLK_GATE_D) |
|
||||
CNP_PWM_CGE_GATING_DISABLE);
|
||||
}
|
||||
|
@ -8517,7 +8522,13 @@ static void cnl_init_clock_gating(struct drm_i915_private *dev_priv)
|
|||
val |= SARBUNIT_CLKGATE_DIS;
|
||||
I915_WRITE(SLICE_UNIT_LEVEL_CLKGATE, val);
|
||||
|
||||
/* Wa_2201832410:cnl */
|
||||
val = I915_READ(SUBSLICE_UNIT_LEVEL_CLKGATE);
|
||||
val |= GWUNIT_CLKGATE_DIS;
|
||||
I915_WRITE(SUBSLICE_UNIT_LEVEL_CLKGATE, val);
|
||||
|
||||
/* WaDisableVFclkgate:cnl */
|
||||
/* WaVFUnitClockGatingDisable:cnl */
|
||||
val = I915_READ(UNSLICE_UNIT_LEVEL_CLKGATE);
|
||||
val |= VFUNIT_CLKGATE_DIS;
|
||||
I915_WRITE(UNSLICE_UNIT_LEVEL_CLKGATE, val);
|
||||
|
|
|
@ -56,6 +56,111 @@
|
|||
#include "intel_drv.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
static inline enum intel_display_power_domain
|
||||
psr_aux_domain(struct intel_dp *intel_dp)
|
||||
{
|
||||
/* CNL HW requires corresponding AUX IOs to be powered up for PSR.
|
||||
* However, for non-A AUX ports the corresponding non-EDP transcoders
|
||||
* would have already enabled power well 2 and DC_OFF. This means we can
|
||||
* acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a
|
||||
* specific AUX_IO reference without powering up any extra wells.
|
||||
* Note that PSR is enabled only on Port A even though this function
|
||||
* returns the correct domain for other ports too.
|
||||
*/
|
||||
return intel_dp->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
|
||||
intel_dp->aux_power_domain;
|
||||
}
|
||||
|
||||
static void psr_aux_io_power_get(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
|
||||
|
||||
if (INTEL_GEN(dev_priv) < 10)
|
||||
return;
|
||||
|
||||
intel_display_power_get(dev_priv, psr_aux_domain(intel_dp));
|
||||
}
|
||||
|
||||
static void psr_aux_io_power_put(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
|
||||
|
||||
if (INTEL_GEN(dev_priv) < 10)
|
||||
return;
|
||||
|
||||
intel_display_power_put(dev_priv, psr_aux_domain(intel_dp));
|
||||
}
|
||||
|
||||
static bool intel_dp_get_y_cord_status(struct intel_dp *intel_dp)
|
||||
{
|
||||
uint8_t psr_caps = 0;
|
||||
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_CAPS, &psr_caps) != 1)
|
||||
return false;
|
||||
return psr_caps & DP_PSR2_SU_Y_COORDINATE_REQUIRED;
|
||||
}
|
||||
|
||||
static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
|
||||
{
|
||||
uint8_t dprx = 0;
|
||||
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
|
||||
&dprx) != 1)
|
||||
return false;
|
||||
return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
|
||||
}
|
||||
|
||||
static bool intel_dp_get_alpm_status(struct intel_dp *intel_dp)
|
||||
{
|
||||
uint8_t alpm_caps = 0;
|
||||
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_RECEIVER_ALPM_CAP,
|
||||
&alpm_caps) != 1)
|
||||
return false;
|
||||
return alpm_caps & DP_ALPM_CAP;
|
||||
}
|
||||
|
||||
void intel_psr_init_dpcd(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *dev_priv =
|
||||
to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
|
||||
|
||||
drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd,
|
||||
sizeof(intel_dp->psr_dpcd));
|
||||
|
||||
if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) {
|
||||
dev_priv->psr.sink_support = true;
|
||||
DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
|
||||
}
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 9 &&
|
||||
(intel_dp->psr_dpcd[0] & DP_PSR2_IS_SUPPORTED)) {
|
||||
uint8_t frame_sync_cap;
|
||||
|
||||
dev_priv->psr.sink_support = true;
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux,
|
||||
DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP,
|
||||
&frame_sync_cap) != 1)
|
||||
frame_sync_cap = 0;
|
||||
dev_priv->psr.aux_frame_sync = frame_sync_cap & DP_AUX_FRAME_SYNC_CAP;
|
||||
/* PSR2 needs frame sync as well */
|
||||
dev_priv->psr.psr2_support = dev_priv->psr.aux_frame_sync;
|
||||
DRM_DEBUG_KMS("PSR2 %s on sink",
|
||||
dev_priv->psr.psr2_support ? "supported" : "not supported");
|
||||
|
||||
if (dev_priv->psr.psr2_support) {
|
||||
dev_priv->psr.y_cord_support =
|
||||
intel_dp_get_y_cord_status(intel_dp);
|
||||
dev_priv->psr.colorimetry_support =
|
||||
intel_dp_get_colorimetry_status(intel_dp);
|
||||
dev_priv->psr.alpm =
|
||||
intel_dp_get_alpm_status(intel_dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
@ -341,6 +446,50 @@ static void hsw_psr_activate(struct intel_dp *intel_dp)
|
|||
hsw_activate_psr1(intel_dp);
|
||||
}
|
||||
|
||||
static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
|
||||
int crtc_hdisplay = crtc_state->base.adjusted_mode.crtc_hdisplay;
|
||||
int crtc_vdisplay = crtc_state->base.adjusted_mode.crtc_vdisplay;
|
||||
int psr_max_h = 0, psr_max_v = 0;
|
||||
|
||||
/*
|
||||
* FIXME psr2_support is messed up. It's both computed
|
||||
* dynamically during PSR enable, and extracted from sink
|
||||
* caps during eDP detection.
|
||||
*/
|
||||
if (!dev_priv->psr.psr2_support)
|
||||
return false;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
|
||||
psr_max_h = 4096;
|
||||
psr_max_v = 2304;
|
||||
} else if (IS_GEN9(dev_priv)) {
|
||||
psr_max_h = 3640;
|
||||
psr_max_v = 2304;
|
||||
}
|
||||
|
||||
if (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v) {
|
||||
DRM_DEBUG_KMS("PSR2 not enabled, resolution %dx%d > max supported %dx%d\n",
|
||||
crtc_hdisplay, crtc_vdisplay,
|
||||
psr_max_h, psr_max_v);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME:enable psr2 only for y-cordinate psr2 panels
|
||||
* After gtc implementation , remove this restriction.
|
||||
*/
|
||||
if (!dev_priv->psr.y_cord_support) {
|
||||
DRM_DEBUG_KMS("PSR2 not enabled, panel does not support Y coordinate\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void intel_psr_compute_config(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
|
@ -403,34 +552,14 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME psr2_support is messed up. It's both computed
|
||||
* dynamically during PSR enable, and extracted from sink
|
||||
* caps during eDP detection.
|
||||
*/
|
||||
if (!dev_priv->psr.psr2_support) {
|
||||
crtc_state->has_psr = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* PSR2 is restricted to work with panel resolutions upto 3200x2000 */
|
||||
if (adjusted_mode->crtc_hdisplay > 3200 ||
|
||||
adjusted_mode->crtc_vdisplay > 2000) {
|
||||
DRM_DEBUG_KMS("PSR2 disabled, panel resolution too big\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME:enable psr2 only for y-cordinate psr2 panels
|
||||
* After gtc implementation , remove this restriction.
|
||||
*/
|
||||
if (!dev_priv->psr.y_cord_support) {
|
||||
DRM_DEBUG_KMS("PSR2 disabled, panel does not support Y coordinate\n");
|
||||
if (!(intel_dp->edp_dpcd[1] & DP_EDP_SET_POWER_CAP)) {
|
||||
DRM_DEBUG_KMS("PSR condition failed: panel lacks power state control\n");
|
||||
return;
|
||||
}
|
||||
|
||||
crtc_state->has_psr = true;
|
||||
crtc_state->has_psr2 = true;
|
||||
crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state);
|
||||
DRM_DEBUG_KMS("Enabling PSR%s\n", crtc_state->has_psr2 ? "2" : "");
|
||||
}
|
||||
|
||||
static void intel_psr_activate(struct intel_dp *intel_dp)
|
||||
|
@ -459,6 +588,8 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp,
|
|||
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
||||
u32 chicken;
|
||||
|
||||
psr_aux_io_power_get(intel_dp);
|
||||
|
||||
if (dev_priv->psr.psr2_support) {
|
||||
chicken = PSR2_VSC_ENABLE_PROG_HEADER;
|
||||
if (dev_priv->psr.y_cord_support)
|
||||
|
@ -617,6 +748,8 @@ static void hsw_psr_disable(struct intel_dp *intel_dp,
|
|||
else
|
||||
WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
|
||||
}
|
||||
|
||||
psr_aux_io_power_put(intel_dp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,7 +66,7 @@ unsigned int intel_ring_update_space(struct intel_ring *ring)
|
|||
}
|
||||
|
||||
static int
|
||||
gen2_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
||||
gen2_render_ring_flush(struct i915_request *rq, u32 mode)
|
||||
{
|
||||
u32 cmd, *cs;
|
||||
|
||||
|
@ -75,19 +75,19 @@ gen2_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
if (mode & EMIT_INVALIDATE)
|
||||
cmd |= MI_READ_FLUSH;
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = cmd;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gen4_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
||||
gen4_render_ring_flush(struct i915_request *rq, u32 mode)
|
||||
{
|
||||
u32 cmd, *cs;
|
||||
|
||||
|
@ -122,17 +122,17 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
cmd = MI_FLUSH;
|
||||
if (mode & EMIT_INVALIDATE) {
|
||||
cmd |= MI_EXE_FLUSH;
|
||||
if (IS_G4X(req->i915) || IS_GEN5(req->i915))
|
||||
if (IS_G4X(rq->i915) || IS_GEN5(rq->i915))
|
||||
cmd |= MI_INVALIDATE_ISP;
|
||||
}
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = cmd;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -175,13 +175,13 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
* really our business. That leaves only stall at scoreboard.
|
||||
*/
|
||||
static int
|
||||
intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
|
||||
intel_emit_post_sync_nonzero_flush(struct i915_request *rq)
|
||||
{
|
||||
u32 scratch_addr =
|
||||
i915_ggtt_offset(req->engine->scratch) + 2 * CACHELINE_BYTES;
|
||||
i915_ggtt_offset(rq->engine->scratch) + 2 * CACHELINE_BYTES;
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 6);
|
||||
cs = intel_ring_begin(rq, 6);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -191,9 +191,9 @@ intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
|
|||
*cs++ = 0; /* low dword */
|
||||
*cs++ = 0; /* high dword */
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
cs = intel_ring_begin(req, 6);
|
||||
cs = intel_ring_begin(rq, 6);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -203,21 +203,21 @@ intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
|
|||
*cs++ = 0;
|
||||
*cs++ = 0;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gen6_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
||||
gen6_render_ring_flush(struct i915_request *rq, u32 mode)
|
||||
{
|
||||
u32 scratch_addr =
|
||||
i915_ggtt_offset(req->engine->scratch) + 2 * CACHELINE_BYTES;
|
||||
i915_ggtt_offset(rq->engine->scratch) + 2 * CACHELINE_BYTES;
|
||||
u32 *cs, flags = 0;
|
||||
int ret;
|
||||
|
||||
/* Force SNB workarounds for PIPE_CONTROL flushes */
|
||||
ret = intel_emit_post_sync_nonzero_flush(req);
|
||||
ret = intel_emit_post_sync_nonzero_flush(rq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -247,7 +247,7 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL;
|
||||
}
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -255,17 +255,17 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
*cs++ = flags;
|
||||
*cs++ = scratch_addr | PIPE_CONTROL_GLOBAL_GTT;
|
||||
*cs++ = 0;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req)
|
||||
gen7_render_ring_cs_stall_wa(struct i915_request *rq)
|
||||
{
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -273,16 +273,16 @@ gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req)
|
|||
*cs++ = PIPE_CONTROL_CS_STALL | PIPE_CONTROL_STALL_AT_SCOREBOARD;
|
||||
*cs++ = 0;
|
||||
*cs++ = 0;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gen7_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
||||
gen7_render_ring_flush(struct i915_request *rq, u32 mode)
|
||||
{
|
||||
u32 scratch_addr =
|
||||
i915_ggtt_offset(req->engine->scratch) + 2 * CACHELINE_BYTES;
|
||||
i915_ggtt_offset(rq->engine->scratch) + 2 * CACHELINE_BYTES;
|
||||
u32 *cs, flags = 0;
|
||||
|
||||
/*
|
||||
|
@ -324,10 +324,10 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
/* Workaround: we must issue a pipe_control with CS-stall bit
|
||||
* set before a pipe_control command that has the state cache
|
||||
* invalidate bit set. */
|
||||
gen7_render_ring_cs_stall_wa(req);
|
||||
gen7_render_ring_cs_stall_wa(rq);
|
||||
}
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -335,7 +335,7 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
*cs++ = flags;
|
||||
*cs++ = scratch_addr;
|
||||
*cs++ = 0;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -531,7 +531,7 @@ static int init_ring_common(struct intel_engine_cs *engine)
|
|||
}
|
||||
|
||||
static void reset_ring_common(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request)
|
||||
struct i915_request *request)
|
||||
{
|
||||
/*
|
||||
* RC6 must be prevented until the reset is complete and the engine
|
||||
|
@ -595,15 +595,15 @@ static void reset_ring_common(struct intel_engine_cs *engine,
|
|||
}
|
||||
}
|
||||
|
||||
static int intel_rcs_ctx_init(struct drm_i915_gem_request *req)
|
||||
static int intel_rcs_ctx_init(struct i915_request *rq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = intel_ring_workarounds_emit(req);
|
||||
ret = intel_ring_workarounds_emit(rq);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = i915_gem_render_state_emit(req);
|
||||
ret = i915_gem_render_state_emit(rq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -661,9 +661,9 @@ static int init_render_ring(struct intel_engine_cs *engine)
|
|||
return init_workarounds_ring(engine);
|
||||
}
|
||||
|
||||
static u32 *gen6_signal(struct drm_i915_gem_request *req, u32 *cs)
|
||||
static u32 *gen6_signal(struct i915_request *rq, u32 *cs)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = req->i915;
|
||||
struct drm_i915_private *dev_priv = rq->i915;
|
||||
struct intel_engine_cs *engine;
|
||||
enum intel_engine_id id;
|
||||
int num_rings = 0;
|
||||
|
@ -674,11 +674,11 @@ static u32 *gen6_signal(struct drm_i915_gem_request *req, u32 *cs)
|
|||
if (!(BIT(engine->hw_id) & GEN6_SEMAPHORES_MASK))
|
||||
continue;
|
||||
|
||||
mbox_reg = req->engine->semaphore.mbox.signal[engine->hw_id];
|
||||
mbox_reg = rq->engine->semaphore.mbox.signal[engine->hw_id];
|
||||
if (i915_mmio_reg_valid(mbox_reg)) {
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(1);
|
||||
*cs++ = i915_mmio_reg_offset(mbox_reg);
|
||||
*cs++ = req->global_seqno;
|
||||
*cs++ = rq->global_seqno;
|
||||
num_rings++;
|
||||
}
|
||||
}
|
||||
|
@ -690,7 +690,7 @@ static u32 *gen6_signal(struct drm_i915_gem_request *req, u32 *cs)
|
|||
|
||||
static void cancel_requests(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_request *request;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&engine->timeline->lock, flags);
|
||||
|
@ -698,7 +698,7 @@ static void cancel_requests(struct intel_engine_cs *engine)
|
|||
/* Mark all submitted requests as skipped. */
|
||||
list_for_each_entry(request, &engine->timeline->requests, link) {
|
||||
GEM_BUG_ON(!request->global_seqno);
|
||||
if (!i915_gem_request_completed(request))
|
||||
if (!i915_request_completed(request))
|
||||
dma_fence_set_error(&request->fence, -EIO);
|
||||
}
|
||||
/* Remaining _unready_ requests will be nop'ed when submitted */
|
||||
|
@ -706,48 +706,46 @@ static void cancel_requests(struct intel_engine_cs *engine)
|
|||
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
||||
}
|
||||
|
||||
static void i9xx_submit_request(struct drm_i915_gem_request *request)
|
||||
static void i9xx_submit_request(struct i915_request *request)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = request->i915;
|
||||
|
||||
i915_gem_request_submit(request);
|
||||
i915_request_submit(request);
|
||||
|
||||
I915_WRITE_TAIL(request->engine,
|
||||
intel_ring_set_tail(request->ring, request->tail));
|
||||
}
|
||||
|
||||
static void i9xx_emit_breadcrumb(struct drm_i915_gem_request *req, u32 *cs)
|
||||
static void i9xx_emit_breadcrumb(struct i915_request *rq, u32 *cs)
|
||||
{
|
||||
*cs++ = MI_STORE_DWORD_INDEX;
|
||||
*cs++ = I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT;
|
||||
*cs++ = req->global_seqno;
|
||||
*cs++ = rq->global_seqno;
|
||||
*cs++ = MI_USER_INTERRUPT;
|
||||
|
||||
req->tail = intel_ring_offset(req, cs);
|
||||
assert_ring_tail_valid(req->ring, req->tail);
|
||||
rq->tail = intel_ring_offset(rq, cs);
|
||||
assert_ring_tail_valid(rq->ring, rq->tail);
|
||||
}
|
||||
|
||||
static const int i9xx_emit_breadcrumb_sz = 4;
|
||||
|
||||
static void gen6_sema_emit_breadcrumb(struct drm_i915_gem_request *req, u32 *cs)
|
||||
static void gen6_sema_emit_breadcrumb(struct i915_request *rq, u32 *cs)
|
||||
{
|
||||
return i9xx_emit_breadcrumb(req,
|
||||
req->engine->semaphore.signal(req, cs));
|
||||
return i9xx_emit_breadcrumb(rq, rq->engine->semaphore.signal(rq, cs));
|
||||
}
|
||||
|
||||
static int
|
||||
gen6_ring_sync_to(struct drm_i915_gem_request *req,
|
||||
struct drm_i915_gem_request *signal)
|
||||
gen6_ring_sync_to(struct i915_request *rq, struct i915_request *signal)
|
||||
{
|
||||
u32 dw1 = MI_SEMAPHORE_MBOX |
|
||||
MI_SEMAPHORE_COMPARE |
|
||||
MI_SEMAPHORE_REGISTER;
|
||||
u32 wait_mbox = signal->engine->semaphore.mbox.wait[req->engine->hw_id];
|
||||
u32 wait_mbox = signal->engine->semaphore.mbox.wait[rq->engine->hw_id];
|
||||
u32 *cs;
|
||||
|
||||
WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID);
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -759,7 +757,7 @@ gen6_ring_sync_to(struct drm_i915_gem_request *req,
|
|||
*cs++ = signal->global_seqno - 1;
|
||||
*cs++ = 0;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -858,17 +856,17 @@ i8xx_irq_disable(struct intel_engine_cs *engine)
|
|||
}
|
||||
|
||||
static int
|
||||
bsd_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
||||
bsd_ring_flush(struct i915_request *rq, u32 mode)
|
||||
{
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_FLUSH;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -911,20 +909,20 @@ hsw_vebox_irq_disable(struct intel_engine_cs *engine)
|
|||
}
|
||||
|
||||
static int
|
||||
i965_emit_bb_start(struct drm_i915_gem_request *req,
|
||||
i965_emit_bb_start(struct i915_request *rq,
|
||||
u64 offset, u32 length,
|
||||
unsigned int dispatch_flags)
|
||||
{
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT | (dispatch_flags &
|
||||
I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE_I965);
|
||||
*cs++ = offset;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -934,13 +932,13 @@ i965_emit_bb_start(struct drm_i915_gem_request *req,
|
|||
#define I830_TLB_ENTRIES (2)
|
||||
#define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT)
|
||||
static int
|
||||
i830_emit_bb_start(struct drm_i915_gem_request *req,
|
||||
i830_emit_bb_start(struct i915_request *rq,
|
||||
u64 offset, u32 len,
|
||||
unsigned int dispatch_flags)
|
||||
{
|
||||
u32 *cs, cs_offset = i915_ggtt_offset(req->engine->scratch);
|
||||
u32 *cs, cs_offset = i915_ggtt_offset(rq->engine->scratch);
|
||||
|
||||
cs = intel_ring_begin(req, 6);
|
||||
cs = intel_ring_begin(rq, 6);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -951,13 +949,13 @@ i830_emit_bb_start(struct drm_i915_gem_request *req,
|
|||
*cs++ = cs_offset;
|
||||
*cs++ = 0xdeadbeef;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
if ((dispatch_flags & I915_DISPATCH_PINNED) == 0) {
|
||||
if (len > I830_BATCH_LIMIT)
|
||||
return -ENOSPC;
|
||||
|
||||
cs = intel_ring_begin(req, 6 + 2);
|
||||
cs = intel_ring_begin(rq, 6 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -974,39 +972,39 @@ i830_emit_bb_start(struct drm_i915_gem_request *req,
|
|||
|
||||
*cs++ = MI_FLUSH;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
/* ... and execute it. */
|
||||
offset = cs_offset;
|
||||
}
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT;
|
||||
*cs++ = offset | (dispatch_flags & I915_DISPATCH_SECURE ? 0 :
|
||||
MI_BATCH_NON_SECURE);
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_emit_bb_start(struct drm_i915_gem_request *req,
|
||||
i915_emit_bb_start(struct i915_request *rq,
|
||||
u64 offset, u32 len,
|
||||
unsigned int dispatch_flags)
|
||||
{
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
*cs++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT;
|
||||
*cs++ = offset | (dispatch_flags & I915_DISPATCH_SECURE ? 0 :
|
||||
MI_BATCH_NON_SECURE);
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1377,7 +1375,7 @@ void intel_legacy_submission_resume(struct drm_i915_private *dev_priv)
|
|||
intel_ring_reset(engine->buffer, 0);
|
||||
}
|
||||
|
||||
static inline int mi_set_context(struct drm_i915_gem_request *rq, u32 flags)
|
||||
static inline int mi_set_context(struct i915_request *rq, u32 flags)
|
||||
{
|
||||
struct drm_i915_private *i915 = rq->i915;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
|
@ -1463,7 +1461,7 @@ static inline int mi_set_context(struct drm_i915_gem_request *rq, u32 flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int remap_l3(struct drm_i915_gem_request *rq, int slice)
|
||||
static int remap_l3(struct i915_request *rq, int slice)
|
||||
{
|
||||
u32 *cs, *remap_info = rq->i915->l3_parity.remap_info[slice];
|
||||
int i;
|
||||
|
@ -1491,7 +1489,7 @@ static int remap_l3(struct drm_i915_gem_request *rq, int slice)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int switch_context(struct drm_i915_gem_request *rq)
|
||||
static int switch_context(struct i915_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
struct i915_gem_context *to_ctx = rq->ctx;
|
||||
|
@ -1561,7 +1559,7 @@ static int switch_context(struct drm_i915_gem_request *rq)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ring_request_alloc(struct drm_i915_gem_request *request)
|
||||
static int ring_request_alloc(struct i915_request *request)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1587,7 +1585,7 @@ static int ring_request_alloc(struct drm_i915_gem_request *request)
|
|||
|
||||
static noinline int wait_for_space(struct intel_ring *ring, unsigned int bytes)
|
||||
{
|
||||
struct drm_i915_gem_request *target;
|
||||
struct i915_request *target;
|
||||
long timeout;
|
||||
|
||||
lockdep_assert_held(&ring->vma->vm->i915->drm.struct_mutex);
|
||||
|
@ -1605,13 +1603,13 @@ static noinline int wait_for_space(struct intel_ring *ring, unsigned int bytes)
|
|||
if (WARN_ON(&target->ring_link == &ring->request_list))
|
||||
return -ENOSPC;
|
||||
|
||||
timeout = i915_wait_request(target,
|
||||
timeout = i915_request_wait(target,
|
||||
I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (timeout < 0)
|
||||
return timeout;
|
||||
|
||||
i915_gem_request_retire_upto(target);
|
||||
i915_request_retire_upto(target);
|
||||
|
||||
intel_ring_update_space(ring);
|
||||
GEM_BUG_ON(ring->space < bytes);
|
||||
|
@ -1634,10 +1632,9 @@ int intel_ring_wait_for_space(struct intel_ring *ring, unsigned int bytes)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32 *intel_ring_begin(struct drm_i915_gem_request *req,
|
||||
unsigned int num_dwords)
|
||||
u32 *intel_ring_begin(struct i915_request *rq, unsigned int num_dwords)
|
||||
{
|
||||
struct intel_ring *ring = req->ring;
|
||||
struct intel_ring *ring = rq->ring;
|
||||
const unsigned int remain_usable = ring->effective_size - ring->emit;
|
||||
const unsigned int bytes = num_dwords * sizeof(u32);
|
||||
unsigned int need_wrap = 0;
|
||||
|
@ -1647,7 +1644,7 @@ u32 *intel_ring_begin(struct drm_i915_gem_request *req,
|
|||
/* Packets must be qword aligned. */
|
||||
GEM_BUG_ON(num_dwords & 1);
|
||||
|
||||
total_bytes = bytes + req->reserved_space;
|
||||
total_bytes = bytes + rq->reserved_space;
|
||||
GEM_BUG_ON(total_bytes > ring->effective_size);
|
||||
|
||||
if (unlikely(total_bytes > remain_usable)) {
|
||||
|
@ -1668,7 +1665,7 @@ u32 *intel_ring_begin(struct drm_i915_gem_request *req,
|
|||
* wrap and only need to effectively wait for the
|
||||
* reserved size from the start of ringbuffer.
|
||||
*/
|
||||
total_bytes = req->reserved_space + remain_actual;
|
||||
total_bytes = rq->reserved_space + remain_actual;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1682,9 +1679,9 @@ u32 *intel_ring_begin(struct drm_i915_gem_request *req,
|
|||
* overallocation and the assumption is that then we never need
|
||||
* to wait (which has the risk of failing with EINTR).
|
||||
*
|
||||
* See also i915_gem_request_alloc() and i915_add_request().
|
||||
* See also i915_request_alloc() and i915_request_add().
|
||||
*/
|
||||
GEM_BUG_ON(!req->reserved_space);
|
||||
GEM_BUG_ON(!rq->reserved_space);
|
||||
|
||||
ret = wait_for_space(ring, total_bytes);
|
||||
if (unlikely(ret))
|
||||
|
@ -1713,29 +1710,28 @@ u32 *intel_ring_begin(struct drm_i915_gem_request *req,
|
|||
}
|
||||
|
||||
/* Align the ring tail to a cacheline boundary */
|
||||
int intel_ring_cacheline_align(struct drm_i915_gem_request *req)
|
||||
int intel_ring_cacheline_align(struct i915_request *rq)
|
||||
{
|
||||
int num_dwords =
|
||||
(req->ring->emit & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
|
||||
int num_dwords = (rq->ring->emit & (CACHELINE_BYTES - 1)) / sizeof(u32);
|
||||
u32 *cs;
|
||||
|
||||
if (num_dwords == 0)
|
||||
return 0;
|
||||
|
||||
num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords;
|
||||
cs = intel_ring_begin(req, num_dwords);
|
||||
num_dwords = CACHELINE_BYTES / sizeof(u32) - num_dwords;
|
||||
cs = intel_ring_begin(rq, num_dwords);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
while (num_dwords--)
|
||||
*cs++ = MI_NOOP;
|
||||
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gen6_bsd_submit_request(struct drm_i915_gem_request *request)
|
||||
static void gen6_bsd_submit_request(struct i915_request *request)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = request->i915;
|
||||
|
||||
|
@ -1772,11 +1768,11 @@ static void gen6_bsd_submit_request(struct drm_i915_gem_request *request)
|
|||
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
|
||||
}
|
||||
|
||||
static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
||||
static int gen6_bsd_ring_flush(struct i915_request *rq, u32 mode)
|
||||
{
|
||||
u32 cmd, *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1802,18 +1798,18 @@ static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
*cs++ = I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT;
|
||||
*cs++ = 0;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hsw_emit_bb_start(struct drm_i915_gem_request *req,
|
||||
hsw_emit_bb_start(struct i915_request *rq,
|
||||
u64 offset, u32 len,
|
||||
unsigned int dispatch_flags)
|
||||
{
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1823,19 +1819,19 @@ hsw_emit_bb_start(struct drm_i915_gem_request *req,
|
|||
MI_BATCH_RESOURCE_STREAMER : 0);
|
||||
/* bit0-7 is the length on GEN6+ */
|
||||
*cs++ = offset;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gen6_emit_bb_start(struct drm_i915_gem_request *req,
|
||||
gen6_emit_bb_start(struct i915_request *rq,
|
||||
u64 offset, u32 len,
|
||||
unsigned int dispatch_flags)
|
||||
{
|
||||
u32 *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 2);
|
||||
cs = intel_ring_begin(rq, 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1843,18 +1839,18 @@ gen6_emit_bb_start(struct drm_i915_gem_request *req,
|
|||
0 : MI_BATCH_NON_SECURE_I965);
|
||||
/* bit0-7 is the length on GEN6+ */
|
||||
*cs++ = offset;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Blitter support (SandyBridge+) */
|
||||
|
||||
static int gen6_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
||||
static int gen6_ring_flush(struct i915_request *rq, u32 mode)
|
||||
{
|
||||
u32 cmd, *cs;
|
||||
|
||||
cs = intel_ring_begin(req, 4);
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
|
@ -1879,7 +1875,7 @@ static int gen6_ring_flush(struct drm_i915_gem_request *req, u32 mode)
|
|||
*cs++ = I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT;
|
||||
*cs++ = 0;
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
#define _INTEL_RINGBUFFER_H_
|
||||
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
#include "i915_gem_batch_pool.h"
|
||||
#include "i915_gem_request.h"
|
||||
#include "i915_gem_timeline.h"
|
||||
|
||||
#include "i915_pmu.h"
|
||||
#include "i915_request.h"
|
||||
#include "i915_selftest.h"
|
||||
|
||||
struct drm_printer;
|
||||
|
@ -90,7 +92,7 @@ hangcheck_action_to_str(const enum intel_engine_hangcheck_action a)
|
|||
|
||||
#define instdone_subslice_mask(dev_priv__) \
|
||||
(INTEL_GEN(dev_priv__) == 7 ? \
|
||||
1 : INTEL_INFO(dev_priv__)->sseu.subslice_mask)
|
||||
1 : INTEL_INFO(dev_priv__)->sseu.subslice_mask[0])
|
||||
|
||||
#define for_each_instdone_slice_subslice(dev_priv__, slice__, subslice__) \
|
||||
for ((slice__) = 0, (subslice__) = 0; \
|
||||
|
@ -115,7 +117,7 @@ struct intel_engine_hangcheck {
|
|||
unsigned long action_timestamp;
|
||||
int deadlock;
|
||||
struct intel_instdone instdone;
|
||||
struct drm_i915_gem_request *active_request;
|
||||
struct i915_request *active_request;
|
||||
bool stalled;
|
||||
};
|
||||
|
||||
|
@ -156,7 +158,10 @@ struct i915_ctx_workarounds {
|
|||
struct i915_vma *vma;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_request;
|
||||
struct i915_request;
|
||||
|
||||
#define I915_MAX_VCS 4
|
||||
#define I915_MAX_VECS 2
|
||||
|
||||
/*
|
||||
* Engine IDs definitions.
|
||||
|
@ -167,8 +172,12 @@ enum intel_engine_id {
|
|||
BCS,
|
||||
VCS,
|
||||
VCS2,
|
||||
VCS3,
|
||||
VCS4,
|
||||
#define _VCS(n) (VCS + (n))
|
||||
VECS
|
||||
VECS,
|
||||
VECS2
|
||||
#define _VECS(n) (VECS + (n))
|
||||
};
|
||||
|
||||
struct i915_priolist {
|
||||
|
@ -200,9 +209,17 @@ struct intel_engine_execlists {
|
|||
bool no_priolist;
|
||||
|
||||
/**
|
||||
* @elsp: the ExecList Submission Port register
|
||||
* @submit_reg: gen-specific execlist submission register
|
||||
* set to the ExecList Submission Port (elsp) register pre-Gen11 and to
|
||||
* the ExecList Submission Queue Contents register array for Gen11+
|
||||
*/
|
||||
u32 __iomem *elsp;
|
||||
u32 __iomem *submit_reg;
|
||||
|
||||
/**
|
||||
* @ctrl_reg: the enhanced execlists control register, used to load the
|
||||
* submit queue on the HW and to request preemptions to idle
|
||||
*/
|
||||
u32 __iomem *ctrl_reg;
|
||||
|
||||
/**
|
||||
* @port: execlist port states
|
||||
|
@ -218,7 +235,7 @@ struct intel_engine_execlists {
|
|||
/**
|
||||
* @request_count: combined request and submission count
|
||||
*/
|
||||
struct drm_i915_gem_request *request_count;
|
||||
struct i915_request *request_count;
|
||||
#define EXECLIST_COUNT_BITS 2
|
||||
#define port_request(p) ptr_mask_bits((p)->request_count, EXECLIST_COUNT_BITS)
|
||||
#define port_count(p) ptr_unmask_bits((p)->request_count, EXECLIST_COUNT_BITS)
|
||||
|
@ -255,6 +272,16 @@ struct intel_engine_execlists {
|
|||
*/
|
||||
unsigned int port_mask;
|
||||
|
||||
/**
|
||||
* @queue_priority: Highest pending priority.
|
||||
*
|
||||
* When we add requests into the queue, or adjust the priority of
|
||||
* executing requests, we compute the maximum priority of those
|
||||
* pending requests. We can then use this value to determine if
|
||||
* we need to preempt the executing requests to service the queue.
|
||||
*/
|
||||
int queue_priority;
|
||||
|
||||
/**
|
||||
* @queue: queue of requests, in priority lists
|
||||
*/
|
||||
|
@ -337,9 +364,9 @@ struct intel_engine_cs {
|
|||
|
||||
spinlock_t rb_lock; /* protects the rb and wraps irq_lock */
|
||||
struct rb_root waiters; /* sorted by retirement, priority */
|
||||
struct rb_root signals; /* sorted by retirement */
|
||||
struct list_head signals; /* sorted by retirement */
|
||||
struct task_struct *signaler; /* used for fence signalling */
|
||||
struct drm_i915_gem_request __rcu *first_signal;
|
||||
|
||||
struct timer_list fake_irq; /* used after a missed interrupt */
|
||||
struct timer_list hangcheck; /* detect missed interrupts */
|
||||
|
||||
|
@ -391,7 +418,7 @@ struct intel_engine_cs {
|
|||
|
||||
int (*init_hw)(struct intel_engine_cs *engine);
|
||||
void (*reset_hw)(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *req);
|
||||
struct i915_request *rq);
|
||||
|
||||
void (*park)(struct intel_engine_cs *engine);
|
||||
void (*unpark)(struct intel_engine_cs *engine);
|
||||
|
@ -402,22 +429,20 @@ struct intel_engine_cs {
|
|||
struct i915_gem_context *ctx);
|
||||
void (*context_unpin)(struct intel_engine_cs *engine,
|
||||
struct i915_gem_context *ctx);
|
||||
int (*request_alloc)(struct drm_i915_gem_request *req);
|
||||
int (*init_context)(struct drm_i915_gem_request *req);
|
||||
int (*request_alloc)(struct i915_request *rq);
|
||||
int (*init_context)(struct i915_request *rq);
|
||||
|
||||
int (*emit_flush)(struct drm_i915_gem_request *request,
|
||||
u32 mode);
|
||||
int (*emit_flush)(struct i915_request *request, u32 mode);
|
||||
#define EMIT_INVALIDATE BIT(0)
|
||||
#define EMIT_FLUSH BIT(1)
|
||||
#define EMIT_BARRIER (EMIT_INVALIDATE | EMIT_FLUSH)
|
||||
int (*emit_bb_start)(struct drm_i915_gem_request *req,
|
||||
int (*emit_bb_start)(struct i915_request *rq,
|
||||
u64 offset, u32 length,
|
||||
unsigned int dispatch_flags);
|
||||
#define I915_DISPATCH_SECURE BIT(0)
|
||||
#define I915_DISPATCH_PINNED BIT(1)
|
||||
#define I915_DISPATCH_RS BIT(2)
|
||||
void (*emit_breadcrumb)(struct drm_i915_gem_request *req,
|
||||
u32 *cs);
|
||||
void (*emit_breadcrumb)(struct i915_request *rq, u32 *cs);
|
||||
int emit_breadcrumb_sz;
|
||||
|
||||
/* Pass the request to the hardware queue (e.g. directly into
|
||||
|
@ -426,7 +451,7 @@ struct intel_engine_cs {
|
|||
* This is called from an atomic context with irqs disabled; must
|
||||
* be irq safe.
|
||||
*/
|
||||
void (*submit_request)(struct drm_i915_gem_request *req);
|
||||
void (*submit_request)(struct i915_request *rq);
|
||||
|
||||
/* Call when the priority on a request has changed and it and its
|
||||
* dependencies may need rescheduling. Note the request itself may
|
||||
|
@ -434,8 +459,7 @@ struct intel_engine_cs {
|
|||
*
|
||||
* Called under the struct_mutex.
|
||||
*/
|
||||
void (*schedule)(struct drm_i915_gem_request *request,
|
||||
int priority);
|
||||
void (*schedule)(struct i915_request *request, int priority);
|
||||
|
||||
/*
|
||||
* Cancel all requests on the hardware, or queued for execution.
|
||||
|
@ -503,9 +527,9 @@ struct intel_engine_cs {
|
|||
} mbox;
|
||||
|
||||
/* AKA wait() */
|
||||
int (*sync_to)(struct drm_i915_gem_request *req,
|
||||
struct drm_i915_gem_request *signal);
|
||||
u32 *(*signal)(struct drm_i915_gem_request *req, u32 *cs);
|
||||
int (*sync_to)(struct i915_request *rq,
|
||||
struct i915_request *signal);
|
||||
u32 *(*signal)(struct i915_request *rq, u32 *cs);
|
||||
} semaphore;
|
||||
|
||||
struct intel_engine_execlists execlists;
|
||||
|
@ -726,14 +750,12 @@ void intel_engine_cleanup(struct intel_engine_cs *engine);
|
|||
|
||||
void intel_legacy_submission_resume(struct drm_i915_private *dev_priv);
|
||||
|
||||
int __must_check intel_ring_cacheline_align(struct drm_i915_gem_request *req);
|
||||
int __must_check intel_ring_cacheline_align(struct i915_request *rq);
|
||||
|
||||
int intel_ring_wait_for_space(struct intel_ring *ring, unsigned int bytes);
|
||||
u32 __must_check *intel_ring_begin(struct drm_i915_gem_request *req,
|
||||
unsigned int n);
|
||||
u32 __must_check *intel_ring_begin(struct i915_request *rq, unsigned int n);
|
||||
|
||||
static inline void
|
||||
intel_ring_advance(struct drm_i915_gem_request *req, u32 *cs)
|
||||
static inline void intel_ring_advance(struct i915_request *rq, u32 *cs)
|
||||
{
|
||||
/* Dummy function.
|
||||
*
|
||||
|
@ -743,22 +765,20 @@ intel_ring_advance(struct drm_i915_gem_request *req, u32 *cs)
|
|||
* reserved for the command packet (i.e. the value passed to
|
||||
* intel_ring_begin()).
|
||||
*/
|
||||
GEM_BUG_ON((req->ring->vaddr + req->ring->emit) != cs);
|
||||
GEM_BUG_ON((rq->ring->vaddr + rq->ring->emit) != cs);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
intel_ring_wrap(const struct intel_ring *ring, u32 pos)
|
||||
static inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos)
|
||||
{
|
||||
return pos & (ring->size - 1);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
intel_ring_offset(const struct drm_i915_gem_request *req, void *addr)
|
||||
static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
|
||||
{
|
||||
/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
|
||||
u32 offset = addr - req->ring->vaddr;
|
||||
GEM_BUG_ON(offset > req->ring->size);
|
||||
return intel_ring_wrap(req->ring, offset);
|
||||
u32 offset = addr - rq->ring->vaddr;
|
||||
GEM_BUG_ON(offset > rq->ring->size);
|
||||
return intel_ring_wrap(rq->ring, offset);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -796,7 +816,7 @@ intel_ring_set_tail(struct intel_ring *ring, unsigned int tail)
|
|||
{
|
||||
/* Whilst writes to the tail are strictly order, there is no
|
||||
* serialisation between readers and the writers. The tail may be
|
||||
* read by i915_gem_request_retire() just as it is being updated
|
||||
* read by i915_request_retire() just as it is being updated
|
||||
* by execlists, as although the breadcrumb is complete, the context
|
||||
* switch hasn't been seen.
|
||||
*/
|
||||
|
@ -838,7 +858,7 @@ static inline u32 intel_engine_last_submit(struct intel_engine_cs *engine)
|
|||
}
|
||||
|
||||
int init_workarounds_ring(struct intel_engine_cs *engine);
|
||||
int intel_ring_workarounds_emit(struct drm_i915_gem_request *req);
|
||||
int intel_ring_workarounds_emit(struct i915_request *rq);
|
||||
|
||||
void intel_engine_get_instdone(struct intel_engine_cs *engine,
|
||||
struct intel_instdone *instdone);
|
||||
|
@ -866,7 +886,7 @@ static inline u32 intel_hws_preempt_done_address(struct intel_engine_cs *engine)
|
|||
int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine);
|
||||
|
||||
static inline void intel_wait_init(struct intel_wait *wait,
|
||||
struct drm_i915_gem_request *rq)
|
||||
struct i915_request *rq)
|
||||
{
|
||||
wait->tsk = current;
|
||||
wait->request = rq;
|
||||
|
@ -892,9 +912,9 @@ intel_wait_update_seqno(struct intel_wait *wait, u32 seqno)
|
|||
|
||||
static inline bool
|
||||
intel_wait_update_request(struct intel_wait *wait,
|
||||
const struct drm_i915_gem_request *rq)
|
||||
const struct i915_request *rq)
|
||||
{
|
||||
return intel_wait_update_seqno(wait, i915_gem_request_global_seqno(rq));
|
||||
return intel_wait_update_seqno(wait, i915_request_global_seqno(rq));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
@ -905,9 +925,9 @@ intel_wait_check_seqno(const struct intel_wait *wait, u32 seqno)
|
|||
|
||||
static inline bool
|
||||
intel_wait_check_request(const struct intel_wait *wait,
|
||||
const struct drm_i915_gem_request *rq)
|
||||
const struct i915_request *rq)
|
||||
{
|
||||
return intel_wait_check_seqno(wait, i915_gem_request_global_seqno(rq));
|
||||
return intel_wait_check_seqno(wait, i915_request_global_seqno(rq));
|
||||
}
|
||||
|
||||
static inline bool intel_wait_complete(const struct intel_wait *wait)
|
||||
|
@ -919,9 +939,8 @@ bool intel_engine_add_wait(struct intel_engine_cs *engine,
|
|||
struct intel_wait *wait);
|
||||
void intel_engine_remove_wait(struct intel_engine_cs *engine,
|
||||
struct intel_wait *wait);
|
||||
void intel_engine_enable_signaling(struct drm_i915_gem_request *request,
|
||||
bool wakeup);
|
||||
void intel_engine_cancel_signaling(struct drm_i915_gem_request *request);
|
||||
void intel_engine_enable_signaling(struct i915_request *request, bool wakeup);
|
||||
void intel_engine_cancel_signaling(struct i915_request *request);
|
||||
|
||||
static inline bool intel_engine_has_waiter(const struct intel_engine_cs *engine)
|
||||
{
|
||||
|
@ -940,7 +959,6 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine);
|
|||
|
||||
void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine);
|
||||
void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
|
||||
bool intel_breadcrumbs_busy(struct intel_engine_cs *engine);
|
||||
|
||||
static inline u32 *gen8_emit_pipe_control(u32 *batch, u32 flags, u32 offset)
|
||||
{
|
||||
|
|
|
@ -130,6 +130,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
|
|||
return "AUX_D";
|
||||
case POWER_DOMAIN_AUX_F:
|
||||
return "AUX_F";
|
||||
case POWER_DOMAIN_AUX_IO_A:
|
||||
return "AUX_IO_A";
|
||||
case POWER_DOMAIN_GMBUS:
|
||||
return "GMBUS";
|
||||
case POWER_DOMAIN_INIT:
|
||||
|
@ -1853,6 +1855,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
|
|||
BIT_ULL(POWER_DOMAIN_INIT))
|
||||
#define CNL_DISPLAY_AUX_A_POWER_DOMAINS ( \
|
||||
BIT_ULL(POWER_DOMAIN_AUX_A) | \
|
||||
BIT_ULL(POWER_DOMAIN_AUX_IO_A) | \
|
||||
BIT_ULL(POWER_DOMAIN_INIT))
|
||||
#define CNL_DISPLAY_AUX_B_POWER_DOMAINS ( \
|
||||
BIT_ULL(POWER_DOMAIN_AUX_B) | \
|
||||
|
|
|
@ -1705,7 +1705,15 @@ static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
|
|||
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
|
||||
|
||||
intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
|
||||
&intel_sdvo->hotplug_active, 2);
|
||||
&intel_sdvo->hotplug_active, 2);
|
||||
}
|
||||
|
||||
static bool intel_sdvo_hotplug(struct intel_encoder *encoder,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
intel_sdvo_enable_hotplug(encoder);
|
||||
|
||||
return intel_encoder_hotplug(encoder, connector);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -2516,7 +2524,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
|
|||
* Some SDVO devices have one-shot hotplug interrupts.
|
||||
* Ensure that they get re-enabled when an interrupt happens.
|
||||
*/
|
||||
intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
|
||||
intel_encoder->hotplug = intel_sdvo_hotplug;
|
||||
intel_sdvo_enable_hotplug(intel_encoder);
|
||||
} else {
|
||||
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
|
||||
|
|
|
@ -361,7 +361,7 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv)
|
|||
goto err_out;
|
||||
|
||||
if (USES_HUC(dev_priv)) {
|
||||
ret = intel_huc_init_hw(huc);
|
||||
ret = intel_huc_fw_upload(huc);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -445,3 +445,48 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv)
|
|||
if (USES_GUC_SUBMISSION(dev_priv))
|
||||
gen9_disable_guc_interrupts(dev_priv);
|
||||
}
|
||||
|
||||
int intel_uc_suspend(struct drm_i915_private *i915)
|
||||
{
|
||||
struct intel_guc *guc = &i915->guc;
|
||||
int err;
|
||||
|
||||
if (!USES_GUC(i915))
|
||||
return 0;
|
||||
|
||||
if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
|
||||
return 0;
|
||||
|
||||
err = intel_guc_suspend(guc);
|
||||
if (err) {
|
||||
DRM_DEBUG_DRIVER("Failed to suspend GuC, err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
gen9_disable_guc_interrupts(i915);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int intel_uc_resume(struct drm_i915_private *i915)
|
||||
{
|
||||
struct intel_guc *guc = &i915->guc;
|
||||
int err;
|
||||
|
||||
if (!USES_GUC(i915))
|
||||
return 0;
|
||||
|
||||
if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
|
||||
return 0;
|
||||
|
||||
if (i915_modparams.guc_log_level)
|
||||
gen9_enable_guc_interrupts(i915);
|
||||
|
||||
err = intel_guc_resume(guc);
|
||||
if (err) {
|
||||
DRM_DEBUG_DRIVER("Failed to resume GuC, err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv);
|
|||
void intel_uc_fini_hw(struct drm_i915_private *dev_priv);
|
||||
int intel_uc_init(struct drm_i915_private *dev_priv);
|
||||
void intel_uc_fini(struct drm_i915_private *dev_priv);
|
||||
int intel_uc_suspend(struct drm_i915_private *dev_priv);
|
||||
int intel_uc_resume(struct drm_i915_private *dev_priv);
|
||||
|
||||
static inline bool intel_uc_is_using_guc(void)
|
||||
{
|
||||
|
|
|
@ -37,6 +37,12 @@ static const char * const forcewake_domain_names[] = {
|
|||
"render",
|
||||
"blitter",
|
||||
"media",
|
||||
"vdbox0",
|
||||
"vdbox1",
|
||||
"vdbox2",
|
||||
"vdbox3",
|
||||
"vebox0",
|
||||
"vebox1",
|
||||
};
|
||||
|
||||
const char *
|
||||
|
@ -774,6 +780,9 @@ void assert_forcewakes_active(struct drm_i915_private *dev_priv,
|
|||
/* We give fast paths for the really cool registers */
|
||||
#define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000)
|
||||
|
||||
#define GEN11_NEEDS_FORCE_WAKE(reg) \
|
||||
((reg) < 0x40000 || ((reg) >= 0x1c0000 && (reg) < 0x1dc000))
|
||||
|
||||
#define __gen6_reg_read_fw_domains(offset) \
|
||||
({ \
|
||||
enum forcewake_domains __fwd; \
|
||||
|
@ -826,6 +835,14 @@ find_fw_domain(struct drm_i915_private *dev_priv, u32 offset)
|
|||
if (!entry)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The list of FW domains depends on the SKU in gen11+ so we
|
||||
* can't determine it statically. We use FORCEWAKE_ALL and
|
||||
* translate it here to the list of available domains.
|
||||
*/
|
||||
if (entry->domains == FORCEWAKE_ALL)
|
||||
return dev_priv->uncore.fw_domains;
|
||||
|
||||
WARN(entry->domains & ~dev_priv->uncore.fw_domains,
|
||||
"Uninitialized forcewake domain(s) 0x%x accessed at 0x%x\n",
|
||||
entry->domains & ~dev_priv->uncore.fw_domains, offset);
|
||||
|
@ -860,6 +877,14 @@ static const struct intel_forcewake_range __vlv_fw_ranges[] = {
|
|||
__fwd; \
|
||||
})
|
||||
|
||||
#define __gen11_fwtable_reg_read_fw_domains(offset) \
|
||||
({ \
|
||||
enum forcewake_domains __fwd = 0; \
|
||||
if (GEN11_NEEDS_FORCE_WAKE((offset))) \
|
||||
__fwd = find_fw_domain(dev_priv, offset); \
|
||||
__fwd; \
|
||||
})
|
||||
|
||||
/* *Must* be sorted by offset! See intel_shadow_table_check(). */
|
||||
static const i915_reg_t gen8_shadowed_regs[] = {
|
||||
RING_TAIL(RENDER_RING_BASE), /* 0x2000 (base) */
|
||||
|
@ -871,6 +896,20 @@ static const i915_reg_t gen8_shadowed_regs[] = {
|
|||
/* TODO: Other registers are not yet used */
|
||||
};
|
||||
|
||||
static const i915_reg_t gen11_shadowed_regs[] = {
|
||||
RING_TAIL(RENDER_RING_BASE), /* 0x2000 (base) */
|
||||
GEN6_RPNSWREQ, /* 0xA008 */
|
||||
GEN6_RC_VIDEO_FREQ, /* 0xA00C */
|
||||
RING_TAIL(BLT_RING_BASE), /* 0x22000 (base) */
|
||||
RING_TAIL(GEN11_BSD_RING_BASE), /* 0x1C0000 (base) */
|
||||
RING_TAIL(GEN11_BSD2_RING_BASE), /* 0x1C4000 (base) */
|
||||
RING_TAIL(GEN11_VEBOX_RING_BASE), /* 0x1C8000 (base) */
|
||||
RING_TAIL(GEN11_BSD3_RING_BASE), /* 0x1D0000 (base) */
|
||||
RING_TAIL(GEN11_BSD4_RING_BASE), /* 0x1D4000 (base) */
|
||||
RING_TAIL(GEN11_VEBOX2_RING_BASE), /* 0x1D8000 (base) */
|
||||
/* TODO: Other registers are not yet used */
|
||||
};
|
||||
|
||||
static int mmio_reg_cmp(u32 key, const i915_reg_t *reg)
|
||||
{
|
||||
u32 offset = i915_mmio_reg_offset(*reg);
|
||||
|
@ -883,14 +922,17 @@ static int mmio_reg_cmp(u32 key, const i915_reg_t *reg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool is_gen8_shadowed(u32 offset)
|
||||
{
|
||||
const i915_reg_t *regs = gen8_shadowed_regs;
|
||||
|
||||
return BSEARCH(offset, regs, ARRAY_SIZE(gen8_shadowed_regs),
|
||||
mmio_reg_cmp);
|
||||
#define __is_genX_shadowed(x) \
|
||||
static bool is_gen##x##_shadowed(u32 offset) \
|
||||
{ \
|
||||
const i915_reg_t *regs = gen##x##_shadowed_regs; \
|
||||
return BSEARCH(offset, regs, ARRAY_SIZE(gen##x##_shadowed_regs), \
|
||||
mmio_reg_cmp); \
|
||||
}
|
||||
|
||||
__is_genX_shadowed(8)
|
||||
__is_genX_shadowed(11)
|
||||
|
||||
#define __gen8_reg_write_fw_domains(offset) \
|
||||
({ \
|
||||
enum forcewake_domains __fwd; \
|
||||
|
@ -929,6 +971,14 @@ static const struct intel_forcewake_range __chv_fw_ranges[] = {
|
|||
__fwd; \
|
||||
})
|
||||
|
||||
#define __gen11_fwtable_reg_write_fw_domains(offset) \
|
||||
({ \
|
||||
enum forcewake_domains __fwd = 0; \
|
||||
if (GEN11_NEEDS_FORCE_WAKE((offset)) && !is_gen11_shadowed(offset)) \
|
||||
__fwd = find_fw_domain(dev_priv, offset); \
|
||||
__fwd; \
|
||||
})
|
||||
|
||||
/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
|
||||
static const struct intel_forcewake_range __gen9_fw_ranges[] = {
|
||||
GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER),
|
||||
|
@ -965,6 +1015,40 @@ static const struct intel_forcewake_range __gen9_fw_ranges[] = {
|
|||
GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_MEDIA),
|
||||
};
|
||||
|
||||
/* *Must* be sorted by offset ranges! See intel_fw_table_check(). */
|
||||
static const struct intel_forcewake_range __gen11_fw_ranges[] = {
|
||||
GEN_FW_RANGE(0x0, 0xaff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0xb00, 0x1fff, 0), /* uncore range */
|
||||
GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x8140, 0x815f, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0x8160, 0x82ff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x8300, 0x84ff, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0x8500, 0x8bff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x8c00, 0x8cff, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0x8d00, 0x93ff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x9400, 0x97ff, FORCEWAKE_ALL),
|
||||
GEN_FW_RANGE(0x9800, 0xafff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0xb000, 0xb47f, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0xb480, 0xdfff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0xe000, 0xe8ff, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0xe900, 0x243ff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x24400, 0x247ff, FORCEWAKE_RENDER),
|
||||
GEN_FW_RANGE(0x24800, 0x3ffff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x40000, 0x1bffff, 0),
|
||||
GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0),
|
||||
GEN_FW_RANGE(0x1c4000, 0x1c7fff, FORCEWAKE_MEDIA_VDBOX1),
|
||||
GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0),
|
||||
GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_BLITTER),
|
||||
GEN_FW_RANGE(0x1d0000, 0x1d3fff, FORCEWAKE_MEDIA_VDBOX2),
|
||||
GEN_FW_RANGE(0x1d4000, 0x1d7fff, FORCEWAKE_MEDIA_VDBOX3),
|
||||
GEN_FW_RANGE(0x1d8000, 0x1dbfff, FORCEWAKE_MEDIA_VEBOX1)
|
||||
};
|
||||
|
||||
static void
|
||||
ilk_dummy_write(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
|
@ -1095,7 +1179,12 @@ func##_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) {
|
|||
}
|
||||
#define __gen6_read(x) __gen_read(gen6, x)
|
||||
#define __fwtable_read(x) __gen_read(fwtable, x)
|
||||
#define __gen11_fwtable_read(x) __gen_read(gen11_fwtable, x)
|
||||
|
||||
__gen11_fwtable_read(8)
|
||||
__gen11_fwtable_read(16)
|
||||
__gen11_fwtable_read(32)
|
||||
__gen11_fwtable_read(64)
|
||||
__fwtable_read(8)
|
||||
__fwtable_read(16)
|
||||
__fwtable_read(32)
|
||||
|
@ -1105,6 +1194,7 @@ __gen6_read(16)
|
|||
__gen6_read(32)
|
||||
__gen6_read(64)
|
||||
|
||||
#undef __gen11_fwtable_read
|
||||
#undef __fwtable_read
|
||||
#undef __gen6_read
|
||||
#undef GEN6_READ_FOOTER
|
||||
|
@ -1181,7 +1271,11 @@ func##_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, boo
|
|||
}
|
||||
#define __gen8_write(x) __gen_write(gen8, x)
|
||||
#define __fwtable_write(x) __gen_write(fwtable, x)
|
||||
#define __gen11_fwtable_write(x) __gen_write(gen11_fwtable, x)
|
||||
|
||||
__gen11_fwtable_write(8)
|
||||
__gen11_fwtable_write(16)
|
||||
__gen11_fwtable_write(32)
|
||||
__fwtable_write(8)
|
||||
__fwtable_write(16)
|
||||
__fwtable_write(32)
|
||||
|
@ -1192,6 +1286,7 @@ __gen6_write(8)
|
|||
__gen6_write(16)
|
||||
__gen6_write(32)
|
||||
|
||||
#undef __gen11_fwtable_write
|
||||
#undef __fwtable_write
|
||||
#undef __gen8_write
|
||||
#undef __gen6_write
|
||||
|
@ -1240,6 +1335,13 @@ static void fw_domain_init(struct drm_i915_private *dev_priv,
|
|||
BUILD_BUG_ON(FORCEWAKE_RENDER != (1 << FW_DOMAIN_ID_RENDER));
|
||||
BUILD_BUG_ON(FORCEWAKE_BLITTER != (1 << FW_DOMAIN_ID_BLITTER));
|
||||
BUILD_BUG_ON(FORCEWAKE_MEDIA != (1 << FW_DOMAIN_ID_MEDIA));
|
||||
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX0 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX0));
|
||||
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX1));
|
||||
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX2 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX2));
|
||||
BUILD_BUG_ON(FORCEWAKE_MEDIA_VDBOX3 != (1 << FW_DOMAIN_ID_MEDIA_VDBOX3));
|
||||
BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX0 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX0));
|
||||
BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX1));
|
||||
|
||||
|
||||
d->mask = BIT(domain_id);
|
||||
|
||||
|
@ -1267,7 +1369,34 @@ static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv)
|
|||
dev_priv->uncore.fw_clear = _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL);
|
||||
}
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 9) {
|
||||
if (INTEL_GEN(dev_priv) >= 11) {
|
||||
int i;
|
||||
|
||||
dev_priv->uncore.funcs.force_wake_get = fw_domains_get;
|
||||
dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
|
||||
fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
|
||||
FORCEWAKE_RENDER_GEN9,
|
||||
FORCEWAKE_ACK_RENDER_GEN9);
|
||||
fw_domain_init(dev_priv, FW_DOMAIN_ID_BLITTER,
|
||||
FORCEWAKE_BLITTER_GEN9,
|
||||
FORCEWAKE_ACK_BLITTER_GEN9);
|
||||
for (i = 0; i < I915_MAX_VCS; i++) {
|
||||
if (!HAS_ENGINE(dev_priv, _VCS(i)))
|
||||
continue;
|
||||
|
||||
fw_domain_init(dev_priv, FW_DOMAIN_ID_MEDIA_VDBOX0 + i,
|
||||
FORCEWAKE_MEDIA_VDBOX_GEN11(i),
|
||||
FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(i));
|
||||
}
|
||||
for (i = 0; i < I915_MAX_VECS; i++) {
|
||||
if (!HAS_ENGINE(dev_priv, _VECS(i)))
|
||||
continue;
|
||||
|
||||
fw_domain_init(dev_priv, FW_DOMAIN_ID_MEDIA_VEBOX0 + i,
|
||||
FORCEWAKE_MEDIA_VEBOX_GEN11(i),
|
||||
FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
|
||||
}
|
||||
} else if (IS_GEN9(dev_priv) || IS_GEN10(dev_priv)) {
|
||||
dev_priv->uncore.funcs.force_wake_get =
|
||||
fw_domains_get_with_fallback;
|
||||
dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
|
||||
|
@ -1422,10 +1551,14 @@ void intel_uncore_init(struct drm_i915_private *dev_priv)
|
|||
ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen8);
|
||||
ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen6);
|
||||
}
|
||||
} else {
|
||||
} else if (IS_GEN(dev_priv, 9, 10)) {
|
||||
ASSIGN_FW_DOMAINS_TABLE(__gen9_fw_ranges);
|
||||
ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, fwtable);
|
||||
ASSIGN_READ_MMIO_VFUNCS(dev_priv, fwtable);
|
||||
} else {
|
||||
ASSIGN_FW_DOMAINS_TABLE(__gen11_fw_ranges);
|
||||
ASSIGN_WRITE_MMIO_VFUNCS(dev_priv, gen11_fwtable);
|
||||
ASSIGN_READ_MMIO_VFUNCS(dev_priv, gen11_fwtable);
|
||||
}
|
||||
|
||||
iosf_mbi_register_pmic_bus_access_notifier(
|
||||
|
@ -1994,7 +2127,9 @@ intel_uncore_forcewake_for_read(struct drm_i915_private *dev_priv,
|
|||
u32 offset = i915_mmio_reg_offset(reg);
|
||||
enum forcewake_domains fw_domains;
|
||||
|
||||
if (HAS_FWTABLE(dev_priv)) {
|
||||
if (INTEL_GEN(dev_priv) >= 11) {
|
||||
fw_domains = __gen11_fwtable_reg_read_fw_domains(offset);
|
||||
} else if (HAS_FWTABLE(dev_priv)) {
|
||||
fw_domains = __fwtable_reg_read_fw_domains(offset);
|
||||
} else if (INTEL_GEN(dev_priv) >= 6) {
|
||||
fw_domains = __gen6_reg_read_fw_domains(offset);
|
||||
|
@ -2015,7 +2150,9 @@ intel_uncore_forcewake_for_write(struct drm_i915_private *dev_priv,
|
|||
u32 offset = i915_mmio_reg_offset(reg);
|
||||
enum forcewake_domains fw_domains;
|
||||
|
||||
if (HAS_FWTABLE(dev_priv) && !IS_VALLEYVIEW(dev_priv)) {
|
||||
if (INTEL_GEN(dev_priv) >= 11) {
|
||||
fw_domains = __gen11_fwtable_reg_write_fw_domains(offset);
|
||||
} else if (HAS_FWTABLE(dev_priv) && !IS_VALLEYVIEW(dev_priv)) {
|
||||
fw_domains = __fwtable_reg_write_fw_domains(offset);
|
||||
} else if (IS_GEN8(dev_priv)) {
|
||||
fw_domains = __gen8_reg_write_fw_domains(offset);
|
||||
|
|
|
@ -37,17 +37,28 @@ enum forcewake_domain_id {
|
|||
FW_DOMAIN_ID_RENDER = 0,
|
||||
FW_DOMAIN_ID_BLITTER,
|
||||
FW_DOMAIN_ID_MEDIA,
|
||||
FW_DOMAIN_ID_MEDIA_VDBOX0,
|
||||
FW_DOMAIN_ID_MEDIA_VDBOX1,
|
||||
FW_DOMAIN_ID_MEDIA_VDBOX2,
|
||||
FW_DOMAIN_ID_MEDIA_VDBOX3,
|
||||
FW_DOMAIN_ID_MEDIA_VEBOX0,
|
||||
FW_DOMAIN_ID_MEDIA_VEBOX1,
|
||||
|
||||
FW_DOMAIN_ID_COUNT
|
||||
};
|
||||
|
||||
enum forcewake_domains {
|
||||
FORCEWAKE_RENDER = BIT(FW_DOMAIN_ID_RENDER),
|
||||
FORCEWAKE_BLITTER = BIT(FW_DOMAIN_ID_BLITTER),
|
||||
FORCEWAKE_MEDIA = BIT(FW_DOMAIN_ID_MEDIA),
|
||||
FORCEWAKE_ALL = (FORCEWAKE_RENDER |
|
||||
FORCEWAKE_BLITTER |
|
||||
FORCEWAKE_MEDIA)
|
||||
FORCEWAKE_RENDER = BIT(FW_DOMAIN_ID_RENDER),
|
||||
FORCEWAKE_BLITTER = BIT(FW_DOMAIN_ID_BLITTER),
|
||||
FORCEWAKE_MEDIA = BIT(FW_DOMAIN_ID_MEDIA),
|
||||
FORCEWAKE_MEDIA_VDBOX0 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX0),
|
||||
FORCEWAKE_MEDIA_VDBOX1 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX1),
|
||||
FORCEWAKE_MEDIA_VDBOX2 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX2),
|
||||
FORCEWAKE_MEDIA_VDBOX3 = BIT(FW_DOMAIN_ID_MEDIA_VDBOX3),
|
||||
FORCEWAKE_MEDIA_VEBOX0 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX0),
|
||||
FORCEWAKE_MEDIA_VEBOX1 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX1),
|
||||
|
||||
FORCEWAKE_ALL = BIT(FW_DOMAIN_ID_COUNT) - 1
|
||||
};
|
||||
|
||||
struct intel_uncore_funcs {
|
||||
|
|
|
@ -964,7 +964,7 @@ static int gpu_write(struct i915_vma *vma,
|
|||
u32 dword,
|
||||
u32 value)
|
||||
{
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct i915_vma *batch;
|
||||
int flags = 0;
|
||||
int err;
|
||||
|
@ -975,7 +975,7 @@ static int gpu_write(struct i915_vma *vma,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
rq = i915_gem_request_alloc(engine, ctx);
|
||||
rq = i915_request_alloc(engine, ctx);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
|
@ -1003,7 +1003,7 @@ static int gpu_write(struct i915_vma *vma,
|
|||
reservation_object_unlock(vma->resv);
|
||||
|
||||
err_request:
|
||||
__i915_add_request(rq, err == 0);
|
||||
__i915_request_add(rq, err == 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ static int gpu_set(struct drm_i915_gem_object *obj,
|
|||
u32 v)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct i915_vma *vma;
|
||||
u32 *cs;
|
||||
int err;
|
||||
|
@ -191,7 +191,7 @@ static int gpu_set(struct drm_i915_gem_object *obj,
|
|||
if (IS_ERR(vma))
|
||||
return PTR_ERR(vma);
|
||||
|
||||
rq = i915_gem_request_alloc(i915->engine[RCS], i915->kernel_context);
|
||||
rq = i915_request_alloc(i915->engine[RCS], i915->kernel_context);
|
||||
if (IS_ERR(rq)) {
|
||||
i915_vma_unpin(vma);
|
||||
return PTR_ERR(rq);
|
||||
|
@ -199,7 +199,7 @@ static int gpu_set(struct drm_i915_gem_object *obj,
|
|||
|
||||
cs = intel_ring_begin(rq, 4);
|
||||
if (IS_ERR(cs)) {
|
||||
__i915_add_request(rq, false);
|
||||
__i915_request_add(rq, false);
|
||||
i915_vma_unpin(vma);
|
||||
return PTR_ERR(cs);
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ static int gpu_set(struct drm_i915_gem_object *obj,
|
|||
reservation_object_add_excl_fence(obj->resv, &rq->fence);
|
||||
reservation_object_unlock(obj->resv);
|
||||
|
||||
__i915_add_request(rq, true);
|
||||
__i915_request_add(rq, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ static int gpu_fill(struct drm_i915_gem_object *obj,
|
|||
struct drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||
struct i915_address_space *vm =
|
||||
ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base;
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct i915_vma *vma;
|
||||
struct i915_vma *batch;
|
||||
unsigned int flags;
|
||||
|
@ -152,7 +152,7 @@ static int gpu_fill(struct drm_i915_gem_object *obj,
|
|||
goto err_vma;
|
||||
}
|
||||
|
||||
rq = i915_gem_request_alloc(engine, ctx);
|
||||
rq = i915_request_alloc(engine, ctx);
|
||||
if (IS_ERR(rq)) {
|
||||
err = PTR_ERR(rq);
|
||||
goto err_batch;
|
||||
|
@ -180,12 +180,12 @@ static int gpu_fill(struct drm_i915_gem_object *obj,
|
|||
reservation_object_add_excl_fence(obj->resv, &rq->fence);
|
||||
reservation_object_unlock(obj->resv);
|
||||
|
||||
__i915_add_request(rq, true);
|
||||
__i915_request_add(rq, true);
|
||||
|
||||
return 0;
|
||||
|
||||
err_request:
|
||||
__i915_add_request(rq, false);
|
||||
__i915_request_add(rq, false);
|
||||
err_batch:
|
||||
i915_vma_unpin(batch);
|
||||
err_vma:
|
||||
|
|
|
@ -407,7 +407,7 @@ static int igt_evict_contexts(void *arg)
|
|||
mutex_lock(&i915->drm.struct_mutex);
|
||||
onstack_fence_init(&fence);
|
||||
do {
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct i915_gem_context *ctx;
|
||||
|
||||
ctx = live_context(i915, file);
|
||||
|
@ -416,7 +416,7 @@ static int igt_evict_contexts(void *arg)
|
|||
|
||||
/* We will need some GGTT space for the rq's context */
|
||||
igt_evict_ctl.fail_if_busy = true;
|
||||
rq = i915_gem_request_alloc(engine, ctx);
|
||||
rq = i915_request_alloc(engine, ctx);
|
||||
igt_evict_ctl.fail_if_busy = false;
|
||||
|
||||
if (IS_ERR(rq)) {
|
||||
|
@ -437,7 +437,7 @@ static int igt_evict_contexts(void *arg)
|
|||
if (err < 0)
|
||||
break;
|
||||
|
||||
i915_add_request(rq);
|
||||
i915_request_add(rq);
|
||||
count++;
|
||||
err = 0;
|
||||
} while(1);
|
||||
|
|
|
@ -436,7 +436,7 @@ next_tiling: ;
|
|||
static int make_obj_busy(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||
struct drm_i915_gem_request *rq;
|
||||
struct i915_request *rq;
|
||||
struct i915_vma *vma;
|
||||
int err;
|
||||
|
||||
|
@ -448,14 +448,14 @@ static int make_obj_busy(struct drm_i915_gem_object *obj)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
rq = i915_gem_request_alloc(i915->engine[RCS], i915->kernel_context);
|
||||
rq = i915_request_alloc(i915->engine[RCS], i915->kernel_context);
|
||||
if (IS_ERR(rq)) {
|
||||
i915_vma_unpin(vma);
|
||||
return PTR_ERR(rq);
|
||||
}
|
||||
|
||||
i915_vma_move_to_active(vma, rq, 0);
|
||||
i915_add_request(rq);
|
||||
i915_request_add(rq);
|
||||
|
||||
i915_gem_object_set_active_reference(obj);
|
||||
i915_vma_unpin(vma);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
selftest(sanitycheck, i915_live_sanitycheck) /* keep first (igt selfcheck) */
|
||||
selftest(uncore, intel_uncore_live_selftests)
|
||||
selftest(requests, i915_gem_request_live_selftests)
|
||||
selftest(requests, i915_request_live_selftests)
|
||||
selftest(objects, i915_gem_object_live_selftests)
|
||||
selftest(dmabuf, i915_gem_dmabuf_live_selftests)
|
||||
selftest(coherency, i915_gem_coherency_live_selftests)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue