mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 15:11:31 +00:00
UAPI Changes:
- Define and parse OA sync properties (Ashutosh) Driver Changes: - Add caller info to xe_gt_reset_async (Nirmoy) - A large forcewake rework / cleanup (Himal) - A g2h response timeout fix (Badal) - A PTL workaround (Vinay) - Handle unreliable MMIO reads during forcewake (Shuicheng) - Ufence user-space access fixes (Nirmoy) - Annotate flexible arrays (Matthew Brost) - Enable GuC lite restore (Fei) - Prevent GuC register capture on VF (Zhanjun) - Show VFs VRAM / LMEM provisioning summary over debugfs (Michal) - Parallel queues fix on GT reset (Nirmoy) - Move reference grabbing to a job's dma-fence (Matt Brost) - Mark a number of local workqueues WQ_MEM_RECLAIM (Matt Brost) - OA synchronization support (Ashutosh) - Capture all available bits of GuC timestamp to GuC log (John) - Increase readability of guc_info debugfs (John) - Add a mmio barrier before GGTT invalidate (Matt Brost) - Don't short-circuit TDR on jobs not started (Matt Brost) -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRskUM7w1oG5rx2IZO4FpNVCsYGvwUCZyNrWgAKCRC4FpNVCsYG v4rZAQDp5hlcb3TP1mPXrUBJ66fGvCx5ncg0jVuYFmGOUGyxBQD/WfvyW8ZQQDtZ QYp5EU2ECE4T7mLgMI9+WA6+1AfDwwA= =1B9X -----END PGP SIGNATURE----- Merge tag 'drm-xe-next-2024-10-31' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-next UAPI Changes: - Define and parse OA sync properties (Ashutosh) Driver Changes: - Add caller info to xe_gt_reset_async (Nirmoy) - A large forcewake rework / cleanup (Himal) - A g2h response timeout fix (Badal) - A PTL workaround (Vinay) - Handle unreliable MMIO reads during forcewake (Shuicheng) - Ufence user-space access fixes (Nirmoy) - Annotate flexible arrays (Matthew Brost) - Enable GuC lite restore (Fei) - Prevent GuC register capture on VF (Zhanjun) - Show VFs VRAM / LMEM provisioning summary over debugfs (Michal) - Parallel queues fix on GT reset (Nirmoy) - Move reference grabbing to a job's dma-fence (Matt Brost) - Mark a number of local workqueues WQ_MEM_RECLAIM (Matt Brost) - OA synchronization support (Ashutosh) - Capture all available bits of GuC timestamp to GuC log (John) - Increase readability of guc_info debugfs (John) - Add a mmio barrier before GGTT invalidate (Matt Brost) - Don't short-circuit TDR on jobs not started (Matt Brost) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Hellstrom <thomas.hellstrom@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/ZyNvA_vZZYR-1eWE@fedora
This commit is contained in:
commit
fb6c5b1fdc
@ -352,6 +352,7 @@ enum xe_guc_klv_ids {
|
||||
GUC_WORKAROUND_KLV_ID_DISABLE_MTP_DURING_ASYNC_COMPUTE = 0x9007,
|
||||
GUC_WA_KLV_NP_RD_WRITE_TO_CLEAR_RCSM_AT_CGP_LATE_RESTORE = 0x9008,
|
||||
GUC_WORKAROUND_KLV_ID_BACK_TO_BACK_RCS_ENGINE_RESET = 0x9009,
|
||||
GUC_WA_KLV_WAKE_POWER_DOMAINS_FOR_OUTBOUND_MMIO = 0x900a,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -42,6 +42,7 @@ bool intel_hdcp_gsc_check_status(struct intel_display *display)
|
||||
struct xe_gt *gt = tile->media_gt;
|
||||
struct xe_gsc *gsc = >->uc.gsc;
|
||||
bool ret = true;
|
||||
unsigned int fw_ref;
|
||||
|
||||
if (!gsc && !xe_uc_fw_is_enabled(&gsc->fw)) {
|
||||
drm_dbg_kms(&xe->drm,
|
||||
@ -50,7 +51,8 @@ bool intel_hdcp_gsc_check_status(struct intel_display *display)
|
||||
}
|
||||
|
||||
xe_pm_runtime_get(xe);
|
||||
if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC)) {
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC);
|
||||
if (!fw_ref) {
|
||||
drm_dbg_kms(&xe->drm,
|
||||
"failed to get forcewake to check proxy status\n");
|
||||
ret = false;
|
||||
@ -60,7 +62,7 @@ bool intel_hdcp_gsc_check_status(struct intel_display *display)
|
||||
if (!xe_gsc_proxy_init_done(gsc))
|
||||
ret = false;
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GSC);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
out:
|
||||
xe_pm_runtime_put(xe);
|
||||
return ret;
|
||||
|
@ -84,7 +84,8 @@
|
||||
#define HUC_LOADING_AGENT_GUC REG_BIT(1)
|
||||
#define GUC_WOPCM_OFFSET_VALID REG_BIT(0)
|
||||
#define GUC_MAX_IDLE_COUNT XE_REG(0xc3e4)
|
||||
#define GUC_PMTIMESTAMP XE_REG(0xc3e8)
|
||||
#define GUC_PMTIMESTAMP_LO XE_REG(0xc3e8)
|
||||
#define GUC_PMTIMESTAMP_HI XE_REG(0xc3ec)
|
||||
|
||||
#define GUC_SEND_INTERRUPT XE_REG(0xc4c8)
|
||||
#define GUC_SEND_TRIGGER REG_BIT(0)
|
||||
|
@ -43,12 +43,11 @@ static void read_l3cc_table(struct xe_gt *gt,
|
||||
{
|
||||
struct kunit *test = kunit_get_current_test();
|
||||
u32 l3cc, l3cc_expected;
|
||||
unsigned int i;
|
||||
unsigned int fw_ref, i;
|
||||
u32 reg_val;
|
||||
u32 ret;
|
||||
|
||||
ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
KUNIT_ASSERT_EQ_MSG(test, ret, 0, "Forcewake Failed.\n");
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
KUNIT_ASSERT_NE_MSG(test, fw_ref, 0, "Forcewake Failed.\n");
|
||||
|
||||
for (i = 0; i < info->num_mocs_regs; i++) {
|
||||
if (!(i & 1)) {
|
||||
@ -72,7 +71,7 @@ static void read_l3cc_table(struct xe_gt *gt,
|
||||
KUNIT_EXPECT_EQ_MSG(test, l3cc_expected, l3cc,
|
||||
"l3cc idx=%u has incorrect val.\n", i);
|
||||
}
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
static void read_mocs_table(struct xe_gt *gt,
|
||||
@ -80,15 +79,14 @@ static void read_mocs_table(struct xe_gt *gt,
|
||||
{
|
||||
struct kunit *test = kunit_get_current_test();
|
||||
u32 mocs, mocs_expected;
|
||||
unsigned int i;
|
||||
unsigned int fw_ref, i;
|
||||
u32 reg_val;
|
||||
u32 ret;
|
||||
|
||||
KUNIT_EXPECT_TRUE_MSG(test, info->unused_entries_index,
|
||||
"Unused entries index should have been defined\n");
|
||||
|
||||
ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
KUNIT_ASSERT_EQ_MSG(test, ret, 0, "Forcewake Failed.\n");
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
KUNIT_ASSERT_NE_MSG(test, fw_ref, 0, "Forcewake Failed.\n");
|
||||
|
||||
for (i = 0; i < info->num_mocs_regs; i++) {
|
||||
if (regs_are_mcr(gt))
|
||||
@ -106,7 +104,7 @@ static void read_mocs_table(struct xe_gt *gt,
|
||||
"mocs reg 0x%x has incorrect val.\n", i);
|
||||
}
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
static int mocs_kernel_test_run_device(struct xe_device *xe)
|
||||
|
@ -90,13 +90,32 @@ static int forcewake_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct xe_device *xe = inode->i_private;
|
||||
struct xe_gt *gt;
|
||||
u8 id;
|
||||
u8 id, last_gt;
|
||||
unsigned int fw_ref;
|
||||
|
||||
xe_pm_runtime_get(xe);
|
||||
for_each_gt(gt, xe, id)
|
||||
XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
for_each_gt(gt, xe, id) {
|
||||
last_gt = id;
|
||||
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
goto err_fw_get;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_fw_get:
|
||||
for_each_gt(gt, xe, id) {
|
||||
if (id < last_gt)
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
else if (id == last_gt)
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
xe_pm_runtime_put(xe);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int forcewake_release(struct inode *inode, struct file *file)
|
||||
@ -106,7 +125,7 @@ static int forcewake_release(struct inode *inode, struct file *file)
|
||||
u8 id;
|
||||
|
||||
for_each_gt(gt, xe, id)
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
xe_pm_runtime_put(xe);
|
||||
|
||||
return 0;
|
||||
|
@ -158,13 +158,15 @@ static void xe_devcoredump_deferred_snap_work(struct work_struct *work)
|
||||
{
|
||||
struct xe_devcoredump_snapshot *ss = container_of(work, typeof(*ss), work);
|
||||
struct xe_devcoredump *coredump = container_of(ss, typeof(*coredump), snapshot);
|
||||
unsigned int fw_ref;
|
||||
|
||||
/* keep going if fw fails as we still want to save the memory and SW data */
|
||||
if (xe_force_wake_get(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL))
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n");
|
||||
xe_vm_snapshot_capture_delayed(ss->vm);
|
||||
xe_guc_exec_queue_snapshot_capture_delayed(ss->ge);
|
||||
xe_force_wake_put(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(ss->gt), fw_ref);
|
||||
|
||||
/* Calculate devcoredump size */
|
||||
ss->read.size = __xe_devcoredump_read(NULL, INT_MAX, coredump);
|
||||
@ -236,8 +238,9 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump,
|
||||
u32 width_mask = (0x1 << q->width) - 1;
|
||||
const char *process_name = "no process";
|
||||
|
||||
int i;
|
||||
unsigned int fw_ref;
|
||||
bool cookie;
|
||||
int i;
|
||||
|
||||
ss->snapshot_time = ktime_get_real();
|
||||
ss->boot_time = ktime_get_boottime();
|
||||
@ -261,11 +264,10 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump,
|
||||
}
|
||||
|
||||
/* keep going if fw fails as we still want to save the memory and SW data */
|
||||
if (xe_force_wake_get(gt_to_fw(q->gt), XE_FORCEWAKE_ALL))
|
||||
xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n");
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(q->gt), XE_FORCEWAKE_ALL);
|
||||
|
||||
ss->guc.log = xe_guc_log_snapshot_capture(&guc->log, true);
|
||||
ss->guc.ct = xe_guc_ct_snapshot_capture(&guc->ct, true);
|
||||
ss->guc.ct = xe_guc_ct_snapshot_capture(&guc->ct);
|
||||
ss->ge = xe_guc_exec_queue_snapshot_capture(q);
|
||||
ss->job = xe_sched_job_snapshot_capture(job);
|
||||
ss->vm = xe_vm_snapshot_capture(q->vm);
|
||||
@ -274,7 +276,7 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump,
|
||||
|
||||
queue_work(system_unbound_wq, &ss->work);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(q->gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(q->gt), fw_ref);
|
||||
dma_fence_end_signalling(cookie);
|
||||
}
|
||||
|
||||
|
@ -604,8 +604,8 @@ int xe_device_probe_early(struct xe_device *xe)
|
||||
static int probe_has_flat_ccs(struct xe_device *xe)
|
||||
{
|
||||
struct xe_gt *gt;
|
||||
unsigned int fw_ref;
|
||||
u32 reg;
|
||||
int err;
|
||||
|
||||
/* Always enabled/disabled, no runtime check to do */
|
||||
if (GRAPHICS_VER(xe) < 20 || !xe->info.has_flat_ccs)
|
||||
@ -613,9 +613,9 @@ static int probe_has_flat_ccs(struct xe_device *xe)
|
||||
|
||||
gt = xe_root_mmio_gt(xe);
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
return err;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
reg = xe_gt_mcr_unicast_read_any(gt, XE2_FLAT_CCS_BASE_RANGE_LOWER);
|
||||
xe->info.has_flat_ccs = (reg & XE2_FLAT_CCS_ENABLE);
|
||||
@ -624,7 +624,8 @@ static int probe_has_flat_ccs(struct xe_device *xe)
|
||||
drm_dbg(&xe->drm,
|
||||
"Flat CCS has been disabled in bios, May lead to performance impact");
|
||||
|
||||
return xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_device_probe(struct xe_device *xe)
|
||||
@ -875,6 +876,7 @@ void xe_device_wmb(struct xe_device *xe)
|
||||
void xe_device_td_flush(struct xe_device *xe)
|
||||
{
|
||||
struct xe_gt *gt;
|
||||
unsigned int fw_ref;
|
||||
u8 id;
|
||||
|
||||
if (!IS_DGFX(xe) || GRAPHICS_VER(xe) < 20)
|
||||
@ -889,7 +891,8 @@ void xe_device_td_flush(struct xe_device *xe)
|
||||
if (xe_gt_is_media_type(gt))
|
||||
continue;
|
||||
|
||||
if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GT))
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
xe_mmio_write32(>->mmio, XE2_TDF_CTRL, TRANSIENT_FLUSH_REQUEST);
|
||||
@ -904,22 +907,22 @@ void xe_device_td_flush(struct xe_device *xe)
|
||||
150, NULL, false))
|
||||
xe_gt_err_once(gt, "TD flush timeout\n");
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
}
|
||||
|
||||
void xe_device_l2_flush(struct xe_device *xe)
|
||||
{
|
||||
struct xe_gt *gt;
|
||||
int err;
|
||||
unsigned int fw_ref;
|
||||
|
||||
gt = xe_root_mmio_gt(xe);
|
||||
|
||||
if (!XE_WA(gt, 16023588340))
|
||||
return;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
spin_lock(>->global_invl_lock);
|
||||
@ -929,7 +932,7 @@ void xe_device_l2_flush(struct xe_device *xe)
|
||||
xe_gt_err_once(gt, "Global invalidation timeout\n");
|
||||
spin_unlock(>->global_invl_lock);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size)
|
||||
|
@ -278,6 +278,7 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file)
|
||||
struct xe_hw_engine *hwe;
|
||||
struct xe_exec_queue *q;
|
||||
u64 gpu_timestamp;
|
||||
unsigned int fw_ref;
|
||||
|
||||
xe_pm_runtime_get(xe);
|
||||
|
||||
@ -303,13 +304,16 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file)
|
||||
continue;
|
||||
|
||||
fw = xe_hw_engine_to_fw_domain(hwe);
|
||||
if (xe_force_wake_get(gt_to_fw(gt), fw)) {
|
||||
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), fw);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, fw)) {
|
||||
hwe = NULL;
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
break;
|
||||
}
|
||||
|
||||
gpu_timestamp = xe_hw_engine_read_timestamp(hwe);
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), fw));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ struct xe_exec_queue {
|
||||
/** @hw_engine_group_link: link into exec queues in the same hw engine group */
|
||||
struct list_head hw_engine_group_link;
|
||||
/** @lrc: logical ring context for this exec queue */
|
||||
struct xe_lrc *lrc[];
|
||||
struct xe_lrc *lrc[] __counted_by(width);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -313,7 +313,7 @@ execlist_run_job(struct drm_sched_job *drm_job)
|
||||
q->ring_ops->emit_job(job);
|
||||
xe_execlist_make_active(exl);
|
||||
|
||||
return dma_fence_get(job->fence);
|
||||
return job->fence;
|
||||
}
|
||||
|
||||
static void execlist_job_free(struct drm_sched_job *drm_job)
|
||||
|
@ -21,15 +21,25 @@ static const char *str_wake_sleep(bool wake)
|
||||
return wake ? "wake" : "sleep";
|
||||
}
|
||||
|
||||
static void domain_init(struct xe_force_wake_domain *domain,
|
||||
static void mark_domain_initialized(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domain_id id)
|
||||
{
|
||||
fw->initialized_domains |= BIT(id);
|
||||
}
|
||||
|
||||
static void init_domain(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domain_id id,
|
||||
struct xe_reg reg, struct xe_reg ack)
|
||||
{
|
||||
struct xe_force_wake_domain *domain = &fw->domains[id];
|
||||
|
||||
domain->id = id;
|
||||
domain->reg_ctl = reg;
|
||||
domain->reg_ack = ack;
|
||||
domain->val = FORCEWAKE_MT(FORCEWAKE_KERNEL);
|
||||
domain->mask = FORCEWAKE_MT_MASK(FORCEWAKE_KERNEL);
|
||||
|
||||
mark_domain_initialized(fw, id);
|
||||
}
|
||||
|
||||
void xe_force_wake_init_gt(struct xe_gt *gt, struct xe_force_wake *fw)
|
||||
@ -43,13 +53,11 @@ void xe_force_wake_init_gt(struct xe_gt *gt, struct xe_force_wake *fw)
|
||||
xe_gt_assert(gt, GRAPHICS_VER(gt_to_xe(gt)) >= 11);
|
||||
|
||||
if (xe->info.graphics_verx100 >= 1270) {
|
||||
domain_init(&fw->domains[XE_FW_DOMAIN_ID_GT],
|
||||
XE_FW_DOMAIN_ID_GT,
|
||||
init_domain(fw, XE_FW_DOMAIN_ID_GT,
|
||||
FORCEWAKE_GT,
|
||||
FORCEWAKE_ACK_GT_MTL);
|
||||
} else {
|
||||
domain_init(&fw->domains[XE_FW_DOMAIN_ID_GT],
|
||||
XE_FW_DOMAIN_ID_GT,
|
||||
init_domain(fw, XE_FW_DOMAIN_ID_GT,
|
||||
FORCEWAKE_GT,
|
||||
FORCEWAKE_ACK_GT);
|
||||
}
|
||||
@ -63,8 +71,7 @@ void xe_force_wake_init_engines(struct xe_gt *gt, struct xe_force_wake *fw)
|
||||
xe_gt_assert(gt, GRAPHICS_VER(gt_to_xe(gt)) >= 11);
|
||||
|
||||
if (!xe_gt_is_media_type(gt))
|
||||
domain_init(&fw->domains[XE_FW_DOMAIN_ID_RENDER],
|
||||
XE_FW_DOMAIN_ID_RENDER,
|
||||
init_domain(fw, XE_FW_DOMAIN_ID_RENDER,
|
||||
FORCEWAKE_RENDER,
|
||||
FORCEWAKE_ACK_RENDER);
|
||||
|
||||
@ -72,8 +79,7 @@ void xe_force_wake_init_engines(struct xe_gt *gt, struct xe_force_wake *fw)
|
||||
if (!(gt->info.engine_mask & BIT(i)))
|
||||
continue;
|
||||
|
||||
domain_init(&fw->domains[XE_FW_DOMAIN_ID_MEDIA_VDBOX0 + j],
|
||||
XE_FW_DOMAIN_ID_MEDIA_VDBOX0 + j,
|
||||
init_domain(fw, XE_FW_DOMAIN_ID_MEDIA_VDBOX0 + j,
|
||||
FORCEWAKE_MEDIA_VDBOX(j),
|
||||
FORCEWAKE_ACK_MEDIA_VDBOX(j));
|
||||
}
|
||||
@ -82,15 +88,13 @@ void xe_force_wake_init_engines(struct xe_gt *gt, struct xe_force_wake *fw)
|
||||
if (!(gt->info.engine_mask & BIT(i)))
|
||||
continue;
|
||||
|
||||
domain_init(&fw->domains[XE_FW_DOMAIN_ID_MEDIA_VEBOX0 + j],
|
||||
XE_FW_DOMAIN_ID_MEDIA_VEBOX0 + j,
|
||||
init_domain(fw, XE_FW_DOMAIN_ID_MEDIA_VEBOX0 + j,
|
||||
FORCEWAKE_MEDIA_VEBOX(j),
|
||||
FORCEWAKE_ACK_MEDIA_VEBOX(j));
|
||||
}
|
||||
|
||||
if (gt->info.engine_mask & BIT(XE_HW_ENGINE_GSCCS0))
|
||||
domain_init(&fw->domains[XE_FW_DOMAIN_ID_GSC],
|
||||
XE_FW_DOMAIN_ID_GSC,
|
||||
init_domain(fw, XE_FW_DOMAIN_ID_GSC,
|
||||
FORCEWAKE_GSC,
|
||||
FORCEWAKE_ACK_GSC);
|
||||
}
|
||||
@ -156,52 +160,108 @@ static int domain_sleep_wait(struct xe_gt *gt,
|
||||
(ffs(tmp__) - 1))) && \
|
||||
domain__->reg_ctl.addr)
|
||||
|
||||
int xe_force_wake_get(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domains domains)
|
||||
/**
|
||||
* xe_force_wake_get() : Increase the domain refcount
|
||||
* @fw: struct xe_force_wake
|
||||
* @domains: forcewake domains to get refcount on
|
||||
*
|
||||
* This function wakes up @domains if they are asleep and takes references.
|
||||
* If requested domain is XE_FORCEWAKE_ALL then only applicable/initialized
|
||||
* domains will be considered for refcount and it is a caller responsibility
|
||||
* to check returned ref if it includes any specific domain by using
|
||||
* xe_force_wake_ref_has_domain() function. Caller must call
|
||||
* xe_force_wake_put() function to decrease incremented refcounts.
|
||||
*
|
||||
* Return: opaque reference to woken domains or zero if none of requested
|
||||
* domains were awake.
|
||||
*/
|
||||
unsigned int __must_check xe_force_wake_get(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domains domains)
|
||||
{
|
||||
struct xe_gt *gt = fw->gt;
|
||||
struct xe_force_wake_domain *domain;
|
||||
enum xe_force_wake_domains tmp, woken = 0;
|
||||
unsigned int ref_incr = 0, awake_rqst = 0, awake_failed = 0;
|
||||
unsigned int tmp, ref_rqst;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
xe_gt_assert(gt, is_power_of_2(domains));
|
||||
xe_gt_assert(gt, domains <= XE_FORCEWAKE_ALL);
|
||||
xe_gt_assert(gt, domains == XE_FORCEWAKE_ALL || fw->initialized_domains & domains);
|
||||
|
||||
ref_rqst = (domains == XE_FORCEWAKE_ALL) ? fw->initialized_domains : domains;
|
||||
spin_lock_irqsave(&fw->lock, flags);
|
||||
for_each_fw_domain_masked(domain, domains, fw, tmp) {
|
||||
for_each_fw_domain_masked(domain, ref_rqst, fw, tmp) {
|
||||
if (!domain->ref++) {
|
||||
woken |= BIT(domain->id);
|
||||
awake_rqst |= BIT(domain->id);
|
||||
domain_wake(gt, domain);
|
||||
}
|
||||
ref_incr |= BIT(domain->id);
|
||||
}
|
||||
for_each_fw_domain_masked(domain, woken, fw, tmp) {
|
||||
ret |= domain_wake_wait(gt, domain);
|
||||
for_each_fw_domain_masked(domain, awake_rqst, fw, tmp) {
|
||||
if (domain_wake_wait(gt, domain) == 0) {
|
||||
fw->awake_domains |= BIT(domain->id);
|
||||
} else {
|
||||
awake_failed |= BIT(domain->id);
|
||||
--domain->ref;
|
||||
}
|
||||
}
|
||||
fw->awake_domains |= woken;
|
||||
ref_incr &= ~awake_failed;
|
||||
spin_unlock_irqrestore(&fw->lock, flags);
|
||||
|
||||
return ret;
|
||||
xe_gt_WARN(gt, awake_failed, "Forcewake domain%s %#x failed to acknowledge awake request\n",
|
||||
str_plural(hweight_long(awake_failed)), awake_failed);
|
||||
|
||||
if (domains == XE_FORCEWAKE_ALL && ref_incr == fw->initialized_domains)
|
||||
ref_incr |= XE_FORCEWAKE_ALL;
|
||||
|
||||
return ref_incr;
|
||||
}
|
||||
|
||||
int xe_force_wake_put(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domains domains)
|
||||
/**
|
||||
* xe_force_wake_put - Decrement the refcount and put domain to sleep if refcount becomes 0
|
||||
* @fw: Pointer to the force wake structure
|
||||
* @fw_ref: return of xe_force_wake_get()
|
||||
*
|
||||
* This function reduces the reference counts for domains in fw_ref. If
|
||||
* refcount for any of the specified domain reaches 0, it puts the domain to sleep
|
||||
* and waits for acknowledgment for domain to sleep within 50 milisec timeout.
|
||||
* Warns in case of timeout of ack from domain.
|
||||
*/
|
||||
void xe_force_wake_put(struct xe_force_wake *fw, unsigned int fw_ref)
|
||||
{
|
||||
struct xe_gt *gt = fw->gt;
|
||||
struct xe_force_wake_domain *domain;
|
||||
enum xe_force_wake_domains tmp, sleep = 0;
|
||||
unsigned int tmp, sleep = 0;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int ack_fail = 0;
|
||||
|
||||
/*
|
||||
* Avoid unnecessary lock and unlock when the function is called
|
||||
* in error path of individual domains.
|
||||
*/
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
if (xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
fw_ref = fw->initialized_domains;
|
||||
|
||||
spin_lock_irqsave(&fw->lock, flags);
|
||||
for_each_fw_domain_masked(domain, domains, fw, tmp) {
|
||||
for_each_fw_domain_masked(domain, fw_ref, fw, tmp) {
|
||||
xe_gt_assert(gt, domain->ref);
|
||||
|
||||
if (!--domain->ref) {
|
||||
sleep |= BIT(domain->id);
|
||||
domain_sleep(gt, domain);
|
||||
}
|
||||
}
|
||||
for_each_fw_domain_masked(domain, sleep, fw, tmp) {
|
||||
ret |= domain_sleep_wait(gt, domain);
|
||||
if (domain_sleep_wait(gt, domain) == 0)
|
||||
fw->awake_domains &= ~BIT(domain->id);
|
||||
else
|
||||
ack_fail |= BIT(domain->id);
|
||||
}
|
||||
fw->awake_domains &= ~sleep;
|
||||
spin_unlock_irqrestore(&fw->lock, flags);
|
||||
|
||||
return ret;
|
||||
xe_gt_WARN(gt, ack_fail, "Forcewake domain%s %#x failed to acknowledge sleep request\n",
|
||||
str_plural(hweight_long(ack_fail)), ack_fail);
|
||||
}
|
||||
|
@ -15,10 +15,9 @@ void xe_force_wake_init_gt(struct xe_gt *gt,
|
||||
struct xe_force_wake *fw);
|
||||
void xe_force_wake_init_engines(struct xe_gt *gt,
|
||||
struct xe_force_wake *fw);
|
||||
int xe_force_wake_get(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domains domains);
|
||||
int xe_force_wake_put(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domains domains);
|
||||
unsigned int __must_check xe_force_wake_get(struct xe_force_wake *fw,
|
||||
enum xe_force_wake_domains domains);
|
||||
void xe_force_wake_put(struct xe_force_wake *fw, unsigned int fw_ref);
|
||||
|
||||
static inline int
|
||||
xe_force_wake_ref(struct xe_force_wake *fw,
|
||||
@ -46,4 +45,20 @@ xe_force_wake_assert_held(struct xe_force_wake *fw,
|
||||
xe_gt_assert(fw->gt, fw->awake_domains & domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_force_wake_ref_has_domain - verifies if the domains are in fw_ref
|
||||
* @fw_ref : the force_wake reference
|
||||
* @domain : forcewake domain to verify
|
||||
*
|
||||
* This function confirms whether the @fw_ref includes a reference to the
|
||||
* specified @domain.
|
||||
*
|
||||
* Return: true if domain is refcounted.
|
||||
*/
|
||||
static inline bool
|
||||
xe_force_wake_ref_has_domain(unsigned int fw_ref, enum xe_force_wake_domains domain)
|
||||
{
|
||||
return fw_ref & domain;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -48,7 +48,7 @@ enum xe_force_wake_domains {
|
||||
XE_FW_MEDIA_VEBOX2 = BIT(XE_FW_DOMAIN_ID_MEDIA_VEBOX2),
|
||||
XE_FW_MEDIA_VEBOX3 = BIT(XE_FW_DOMAIN_ID_MEDIA_VEBOX3),
|
||||
XE_FW_GSC = BIT(XE_FW_DOMAIN_ID_GSC),
|
||||
XE_FORCEWAKE_ALL = BIT(XE_FW_DOMAIN_ID_COUNT) - 1
|
||||
XE_FORCEWAKE_ALL = BIT(XE_FW_DOMAIN_ID_COUNT)
|
||||
};
|
||||
|
||||
/**
|
||||
@ -78,7 +78,9 @@ struct xe_force_wake {
|
||||
/** @lock: protects everything force wake struct */
|
||||
spinlock_t lock;
|
||||
/** @awake_domains: mask of all domains awake */
|
||||
enum xe_force_wake_domains awake_domains;
|
||||
unsigned int awake_domains;
|
||||
/** @initialized_domains: mask of all initialized domains */
|
||||
unsigned int initialized_domains;
|
||||
/** @domains: force wake domains */
|
||||
struct xe_force_wake_domain domains[XE_FW_DOMAIN_ID_COUNT];
|
||||
};
|
||||
|
@ -246,7 +246,7 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
|
||||
else
|
||||
ggtt->pt_ops = &xelp_pt_ops;
|
||||
|
||||
ggtt->wq = alloc_workqueue("xe-ggtt-wq", 0, 0);
|
||||
ggtt->wq = alloc_workqueue("xe-ggtt-wq", 0, WQ_MEM_RECLAIM);
|
||||
|
||||
drm_mm_init(&ggtt->mm, xe_wopcm_size(xe),
|
||||
ggtt->size - xe_wopcm_size(xe));
|
||||
@ -409,7 +409,7 @@ static void xe_ggtt_invalidate(struct xe_ggtt *ggtt)
|
||||
* vs. correct GGTT page. Not particularly a hot code path so blindly
|
||||
* do a mmio read here which results in GuC reading correct GGTT page.
|
||||
*/
|
||||
xe_mmio_read32(&xe_root_mmio_gt(xe)->mmio, VF_CAP_REG);
|
||||
xe_mmio_read32(xe_root_tile_mmio(xe), VF_CAP_REG);
|
||||
|
||||
/* Each GT in a tile has its own TLB to cache GGTT lookups */
|
||||
ggtt_invalidate_gt_tlb(ggtt->tile->primary_gt);
|
||||
|
@ -261,19 +261,17 @@ static int gsc_upload_and_init(struct xe_gsc *gsc)
|
||||
{
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
struct xe_tile *tile = gt_to_tile(gt);
|
||||
unsigned int fw_ref;
|
||||
int ret;
|
||||
|
||||
if (XE_WA(tile->primary_gt, 14018094691)) {
|
||||
ret = xe_force_wake_get(gt_to_fw(tile->primary_gt), XE_FORCEWAKE_ALL);
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(tile->primary_gt), XE_FORCEWAKE_ALL);
|
||||
|
||||
/*
|
||||
* If the forcewake fails we want to keep going, because the worst
|
||||
* case outcome in failing to apply the WA is that PXP won't work,
|
||||
* which is not fatal. We still throw a warning so the issue is
|
||||
* seen if it happens.
|
||||
* which is not fatal. Forcewake get warns implicitly in case of failure
|
||||
*/
|
||||
xe_gt_WARN_ON(tile->primary_gt, ret);
|
||||
|
||||
xe_gt_mcr_multicast_write(tile->primary_gt,
|
||||
EU_SYSTOLIC_LIC_THROTTLE_CTL_WITH_LOCK,
|
||||
EU_SYSTOLIC_LIC_THROTTLE_CTL_LOCK_BIT);
|
||||
@ -282,7 +280,7 @@ static int gsc_upload_and_init(struct xe_gsc *gsc)
|
||||
ret = gsc_upload(gsc);
|
||||
|
||||
if (XE_WA(tile->primary_gt, 14018094691))
|
||||
xe_force_wake_put(gt_to_fw(tile->primary_gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(tile->primary_gt), fw_ref);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -352,6 +350,7 @@ static void gsc_work(struct work_struct *work)
|
||||
struct xe_gsc *gsc = container_of(work, typeof(*gsc), work);
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
unsigned int fw_ref;
|
||||
u32 actions;
|
||||
int ret;
|
||||
|
||||
@ -361,7 +360,7 @@ static void gsc_work(struct work_struct *work)
|
||||
spin_unlock_irq(&gsc->lock);
|
||||
|
||||
xe_pm_runtime_get(xe);
|
||||
xe_gt_WARN_ON(gt, xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC);
|
||||
|
||||
if (actions & GSC_ACTION_ER_COMPLETE) {
|
||||
ret = gsc_er_complete(gt);
|
||||
@ -381,7 +380,7 @@ static void gsc_work(struct work_struct *work)
|
||||
xe_gsc_proxy_request_handler(gsc);
|
||||
|
||||
out:
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GSC);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_pm_runtime_put(xe);
|
||||
}
|
||||
|
||||
@ -601,7 +600,7 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p)
|
||||
{
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
struct xe_mmio *mmio = >->mmio;
|
||||
int err;
|
||||
unsigned int fw_ref;
|
||||
|
||||
xe_uc_fw_print(&gsc->fw, p);
|
||||
|
||||
@ -610,8 +609,8 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p)
|
||||
if (!xe_uc_fw_is_enabled(&gsc->fw))
|
||||
return;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
drm_printf(p, "\nHECI1 FWSTS: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
@ -622,5 +621,5 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p)
|
||||
xe_mmio_read32(mmio, HECI_FWSTS5(MTL_GSC_HECI1_BASE)),
|
||||
xe_mmio_read32(mmio, HECI_FWSTS6(MTL_GSC_HECI1_BASE)));
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GSC);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
@ -450,22 +450,21 @@ void xe_gsc_proxy_remove(struct xe_gsc *gsc)
|
||||
{
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int err = 0;
|
||||
unsigned int fw_ref = 0;
|
||||
|
||||
if (!gsc->proxy.component_added)
|
||||
return;
|
||||
|
||||
/* disable HECI2 IRQs */
|
||||
xe_pm_runtime_get(xe);
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC);
|
||||
if (!fw_ref)
|
||||
xe_gt_err(gt, "failed to get forcewake to disable GSC interrupts\n");
|
||||
|
||||
/* try do disable irq even if forcewake failed */
|
||||
gsc_proxy_irq_toggle(gsc, false);
|
||||
|
||||
if (!err)
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GSC);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_pm_runtime_put(xe);
|
||||
|
||||
xe_gsc_wait_for_worker_completion(gsc);
|
||||
|
@ -77,7 +77,8 @@ struct xe_gt *xe_gt_alloc(struct xe_tile *tile)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gt->tile = tile;
|
||||
gt->ordered_wq = alloc_ordered_workqueue("gt-ordered-wq", 0);
|
||||
gt->ordered_wq = alloc_ordered_workqueue("gt-ordered-wq",
|
||||
WQ_MEM_RECLAIM);
|
||||
|
||||
err = drmm_add_action_or_reset(>_to_xe(gt)->drm, gt_fini, gt);
|
||||
if (err)
|
||||
@ -97,14 +98,14 @@ void xe_gt_sanitize(struct xe_gt *gt)
|
||||
|
||||
static void xe_gt_enable_host_l2_vram(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
u32 reg;
|
||||
int err;
|
||||
|
||||
if (!XE_WA(gt, 16023588340))
|
||||
return;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (WARN_ON(err))
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
if (!xe_gt_is_media_type(gt)) {
|
||||
@ -114,13 +115,13 @@ static void xe_gt_enable_host_l2_vram(struct xe_gt *gt)
|
||||
}
|
||||
|
||||
xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0x3);
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
static void xe_gt_disable_host_l2_vram(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
u32 reg;
|
||||
int err;
|
||||
|
||||
if (!XE_WA(gt, 16023588340))
|
||||
return;
|
||||
@ -128,15 +129,15 @@ static void xe_gt_disable_host_l2_vram(struct xe_gt *gt)
|
||||
if (xe_gt_is_media_type(gt))
|
||||
return;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (WARN_ON(err))
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMREQSTRM_CTRL);
|
||||
reg &= ~CG_DIS_CNTLBUS;
|
||||
xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -402,11 +403,14 @@ static void dump_pat_on_error(struct xe_gt *gt)
|
||||
|
||||
static int gt_fw_domain_init(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
int err, i;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref) {
|
||||
err = -ETIMEDOUT;
|
||||
goto err_hw_fence_irq;
|
||||
}
|
||||
|
||||
if (!xe_gt_is_media_type(gt)) {
|
||||
err = xe_ggtt_init(gt_to_tile(gt)->mem.ggtt);
|
||||
@ -441,14 +445,12 @@ static int gt_fw_domain_init(struct xe_gt *gt)
|
||||
*/
|
||||
gt->info.gmdid = xe_mmio_read32(>->mmio, GMD_ID);
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
XE_WARN_ON(err);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return 0;
|
||||
|
||||
err_force_wake:
|
||||
dump_pat_on_error(gt);
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
err_hw_fence_irq:
|
||||
for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i)
|
||||
xe_hw_fence_irq_finish(>->fence_irq[i]);
|
||||
@ -458,11 +460,14 @@ err_hw_fence_irq:
|
||||
|
||||
static int all_fw_domain_init(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
int err, i;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (err)
|
||||
goto err_hw_fence_irq;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
err = -ETIMEDOUT;
|
||||
goto err_force_wake;
|
||||
}
|
||||
|
||||
xe_gt_mcr_set_implicit_defaults(gt);
|
||||
xe_reg_sr_apply_mmio(>->reg_sr, gt);
|
||||
@ -526,14 +531,12 @@ static int all_fw_domain_init(struct xe_gt *gt)
|
||||
if (IS_SRIOV_PF(gt_to_xe(gt)))
|
||||
xe_gt_sriov_pf_init_hw(gt);
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
XE_WARN_ON(err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
|
||||
return 0;
|
||||
|
||||
err_force_wake:
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
err_hw_fence_irq:
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i)
|
||||
xe_hw_fence_irq_finish(>->fence_irq[i]);
|
||||
|
||||
@ -546,11 +549,12 @@ err_hw_fence_irq:
|
||||
*/
|
||||
int xe_gt_init_hwconfig(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
int err;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
goto out;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
xe_gt_mcr_init_early(gt);
|
||||
xe_pat_init(gt);
|
||||
@ -568,8 +572,7 @@ int xe_gt_init_hwconfig(struct xe_gt *gt)
|
||||
xe_gt_enable_host_l2_vram(gt);
|
||||
|
||||
out_fw:
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
out:
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -764,6 +767,7 @@ static int do_gt_restart(struct xe_gt *gt)
|
||||
|
||||
static int gt_reset(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
int err;
|
||||
|
||||
if (xe_device_wedged(gt_to_xe(gt)))
|
||||
@ -784,9 +788,11 @@ static int gt_reset(struct xe_gt *gt)
|
||||
|
||||
xe_gt_sanitize(gt);
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (err)
|
||||
goto err_msg;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
err = -ETIMEDOUT;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
xe_uc_gucrc_disable(>->uc);
|
||||
xe_uc_stop_prepare(>->uc);
|
||||
@ -804,8 +810,7 @@ static int gt_reset(struct xe_gt *gt)
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
XE_WARN_ON(err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_pm_runtime_put(gt_to_xe(gt));
|
||||
|
||||
xe_gt_info(gt, "reset done\n");
|
||||
@ -813,8 +818,7 @@ static int gt_reset(struct xe_gt *gt)
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
err_msg:
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
XE_WARN_ON(xe_uc_start(>->uc));
|
||||
err_fail:
|
||||
xe_gt_err(gt, "reset failed (%pe)\n", ERR_PTR(err));
|
||||
@ -834,7 +838,7 @@ static void gt_reset_worker(struct work_struct *w)
|
||||
|
||||
void xe_gt_reset_async(struct xe_gt *gt)
|
||||
{
|
||||
xe_gt_info(gt, "trying reset\n");
|
||||
xe_gt_info(gt, "trying reset from %ps\n", __builtin_return_address(0));
|
||||
|
||||
/* Don't do a reset while one is already in flight */
|
||||
if (!xe_fault_inject_gt_reset() && xe_uc_reset_prepare(>->uc))
|
||||
@ -846,22 +850,25 @@ void xe_gt_reset_async(struct xe_gt *gt)
|
||||
|
||||
void xe_gt_suspend_prepare(struct xe_gt *gt)
|
||||
{
|
||||
XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
unsigned int fw_ref;
|
||||
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
|
||||
xe_uc_stop_prepare(>->uc);
|
||||
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
int xe_gt_suspend(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
int err;
|
||||
|
||||
xe_gt_dbg(gt, "suspending\n");
|
||||
xe_gt_sanitize(gt);
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
goto err_msg;
|
||||
|
||||
err = xe_uc_suspend(>->uc);
|
||||
@ -872,14 +879,15 @@ int xe_gt_suspend(struct xe_gt *gt)
|
||||
|
||||
xe_gt_disable_host_l2_vram(gt);
|
||||
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_gt_dbg(gt, "suspended\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_force_wake:
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
err_msg:
|
||||
err = -ETIMEDOUT;
|
||||
err_force_wake:
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_gt_err(gt, "suspend failed (%pe)\n", ERR_PTR(err));
|
||||
|
||||
return err;
|
||||
@ -887,9 +895,11 @@ err_msg:
|
||||
|
||||
void xe_gt_shutdown(struct xe_gt *gt)
|
||||
{
|
||||
xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
unsigned int fw_ref;
|
||||
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
do_gt_reset(gt);
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -914,11 +924,12 @@ int xe_gt_sanitize_freq(struct xe_gt *gt)
|
||||
|
||||
int xe_gt_resume(struct xe_gt *gt)
|
||||
{
|
||||
unsigned int fw_ref;
|
||||
int err;
|
||||
|
||||
xe_gt_dbg(gt, "resuming\n");
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
goto err_msg;
|
||||
|
||||
err = do_gt_restart(gt);
|
||||
@ -927,14 +938,15 @@ int xe_gt_resume(struct xe_gt *gt)
|
||||
|
||||
xe_gt_idle_enable_pg(gt);
|
||||
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_gt_dbg(gt, "resumed\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_force_wake:
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
err_msg:
|
||||
err = -ETIMEDOUT;
|
||||
err_force_wake:
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_gt_err(gt, "resume failed (%pe)\n", ERR_PTR(err));
|
||||
|
||||
return err;
|
||||
|
@ -90,22 +90,21 @@ static int hw_engines(struct xe_gt *gt, struct drm_printer *p)
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
struct xe_hw_engine *hwe;
|
||||
enum xe_hw_engine_id id;
|
||||
int err;
|
||||
unsigned int fw_ref;
|
||||
|
||||
xe_pm_runtime_get(xe);
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (err) {
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
xe_pm_runtime_put(xe);
|
||||
return err;
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
for_each_hw_engine(hwe, gt, id)
|
||||
xe_hw_engine_print(hwe, p);
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_pm_runtime_put(xe);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt)
|
||||
struct xe_gt_idle *gtidle = >->gtidle;
|
||||
struct xe_mmio *mmio = >->mmio;
|
||||
u32 vcs_mask, vecs_mask;
|
||||
unsigned int fw_ref;
|
||||
int i, j;
|
||||
|
||||
if (IS_SRIOV_VF(xe))
|
||||
@ -127,7 +128,7 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt)
|
||||
VDN_MFXVDENC_POWERGATE_ENABLE(j));
|
||||
}
|
||||
|
||||
XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FW_GT));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (xe->info.skip_guc_pc) {
|
||||
/*
|
||||
* GuC sets the hysteresis value when GuC PC is enabled
|
||||
@ -138,12 +139,13 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt)
|
||||
}
|
||||
|
||||
xe_mmio_write32(mmio, POWERGATE_ENABLE, gtidle->powergate_enable);
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FW_GT));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
void xe_gt_idle_disable_pg(struct xe_gt *gt)
|
||||
{
|
||||
struct xe_gt_idle *gtidle = >->gtidle;
|
||||
unsigned int fw_ref;
|
||||
|
||||
if (IS_SRIOV_VF(gt_to_xe(gt)))
|
||||
return;
|
||||
@ -151,9 +153,9 @@ void xe_gt_idle_disable_pg(struct xe_gt *gt)
|
||||
xe_device_assert_mem_access(gt_to_xe(gt));
|
||||
gtidle->powergate_enable = 0;
|
||||
|
||||
XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FW_GT));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_mmio_write32(>->mmio, POWERGATE_ENABLE, gtidle->powergate_enable);
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FW_GT));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,7 +174,8 @@ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p)
|
||||
enum xe_gt_idle_state state;
|
||||
u32 pg_enabled, pg_status = 0;
|
||||
u32 vcs_mask, vecs_mask;
|
||||
int err, n;
|
||||
unsigned int fw_ref;
|
||||
int n;
|
||||
/*
|
||||
* Media Slices
|
||||
*
|
||||
@ -208,14 +211,14 @@ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p)
|
||||
|
||||
/* Do not wake the GT to read powergating status */
|
||||
if (state != GT_IDLE_C6) {
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
return err;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
pg_enabled = xe_mmio_read32(>->mmio, POWERGATE_ENABLE);
|
||||
pg_status = xe_mmio_read32(>->mmio, POWERGATE_DOMAIN_STATUS);
|
||||
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FW_GT));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
if (gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK) {
|
||||
@ -298,13 +301,14 @@ static void gt_idle_fini(void *arg)
|
||||
{
|
||||
struct kobject *kobj = arg;
|
||||
struct xe_gt *gt = kobj_to_gt(kobj->parent);
|
||||
unsigned int fw_ref;
|
||||
|
||||
xe_gt_idle_disable_pg(gt);
|
||||
|
||||
if (gt_to_xe(gt)->info.skip_guc_pc) {
|
||||
XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FW_GT));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_gt_idle_disable_c6(gt);
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
sysfs_remove_files(kobj, gt_idle_attrs);
|
||||
|
@ -2376,6 +2376,41 @@ int xe_gt_sriov_pf_config_print_dbs(struct xe_gt *gt, struct drm_printer *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_gt_sriov_pf_config_print_lmem - Print LMEM configurations.
|
||||
* @gt: the &xe_gt
|
||||
* @p: the &drm_printer
|
||||
*
|
||||
* Print LMEM allocations across all VFs.
|
||||
* VFs without LMEM allocation are skipped.
|
||||
*
|
||||
* This function can only be called on PF.
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_gt_sriov_pf_config_print_lmem(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(gt_to_xe(gt));
|
||||
const struct xe_gt_sriov_config *config;
|
||||
char buf[10];
|
||||
|
||||
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
||||
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
||||
|
||||
for (n = 1; n <= total_vfs; n++) {
|
||||
config = >->sriov.pf.vfs[n].config;
|
||||
if (!config->lmem_obj)
|
||||
continue;
|
||||
|
||||
string_get_size(config->lmem_obj->size, 1, STRING_UNITS_2,
|
||||
buf, sizeof(buf));
|
||||
drm_printf(p, "VF%u:\t%zu\t(%s)\n",
|
||||
n, config->lmem_obj->size, buf);
|
||||
}
|
||||
|
||||
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_gt_sriov_pf_config_print_available_ggtt - Print available GGTT ranges.
|
||||
* @gt: the &xe_gt
|
||||
|
@ -65,6 +65,7 @@ void xe_gt_sriov_pf_config_restart(struct xe_gt *gt);
|
||||
int xe_gt_sriov_pf_config_print_ggtt(struct xe_gt *gt, struct drm_printer *p);
|
||||
int xe_gt_sriov_pf_config_print_ctxs(struct xe_gt *gt, struct drm_printer *p);
|
||||
int xe_gt_sriov_pf_config_print_dbs(struct xe_gt *gt, struct drm_printer *p);
|
||||
int xe_gt_sriov_pf_config_print_lmem(struct xe_gt *gt, struct drm_printer *p);
|
||||
|
||||
int xe_gt_sriov_pf_config_print_available_ggtt(struct xe_gt *gt, struct drm_printer *p);
|
||||
|
||||
|
@ -81,6 +81,11 @@ static const struct drm_info_list pf_info[] = {
|
||||
.show = xe_gt_debugfs_simple_show,
|
||||
.data = xe_gt_sriov_pf_config_print_dbs,
|
||||
},
|
||||
{
|
||||
"lmem_provisioned",
|
||||
.show = xe_gt_debugfs_simple_show,
|
||||
.data = xe_gt_sriov_pf_config_print_lmem,
|
||||
},
|
||||
{
|
||||
"runtime_registers",
|
||||
.show = xe_gt_debugfs_simple_show,
|
||||
|
@ -268,6 +268,7 @@ static int xe_gt_tlb_invalidation_guc(struct xe_gt *gt,
|
||||
int xe_gt_tlb_invalidation_ggtt(struct xe_gt *gt)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
unsigned int fw_ref;
|
||||
|
||||
if (xe_guc_ct_enabled(>->uc.guc.ct) &&
|
||||
gt->uc.guc.submission_state.enabled) {
|
||||
@ -286,7 +287,7 @@ int xe_gt_tlb_invalidation_ggtt(struct xe_gt *gt)
|
||||
if (IS_SRIOV_VF(xe))
|
||||
return 0;
|
||||
|
||||
xe_gt_WARN_ON(gt, xe_force_wake_get(gt_to_fw(gt), XE_FW_GT));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (xe->info.platform == XE_PVC || GRAPHICS_VER(xe) >= 20) {
|
||||
xe_mmio_write32(mmio, PVC_GUC_TLB_INV_DESC1,
|
||||
PVC_GUC_TLB_INV_DESC1_INVALIDATE);
|
||||
@ -296,7 +297,7 @@ int xe_gt_tlb_invalidation_ggtt(struct xe_gt *gt)
|
||||
xe_mmio_write32(mmio, GUC_TLB_INV_CR,
|
||||
GUC_TLB_INV_CR_INVALIDATE);
|
||||
}
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -70,7 +70,7 @@ static u32 guc_ctl_debug_flags(struct xe_guc *guc)
|
||||
|
||||
static u32 guc_ctl_feature_flags(struct xe_guc *guc)
|
||||
{
|
||||
u32 flags = 0;
|
||||
u32 flags = GUC_CTL_ENABLE_LITE_RESTORE;
|
||||
|
||||
if (!guc_to_xe(guc)->info.skip_guc_pc)
|
||||
flags |= GUC_CTL_ENABLE_SLPC;
|
||||
@ -248,10 +248,11 @@ static void guc_fini_hw(void *arg)
|
||||
{
|
||||
struct xe_guc *guc = arg;
|
||||
struct xe_gt *gt = guc_to_gt(guc);
|
||||
unsigned int fw_ref;
|
||||
|
||||
xe_gt_WARN_ON(gt, xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
xe_uc_fini_hw(&guc_to_gt(guc)->uc);
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1155,14 +1156,14 @@ int xe_guc_start(struct xe_guc *guc)
|
||||
void xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p)
|
||||
{
|
||||
struct xe_gt *gt = guc_to_gt(guc);
|
||||
unsigned int fw_ref;
|
||||
u32 status;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
xe_uc_fw_print(&guc->fw, p);
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
status = xe_mmio_read32(>->mmio, GUC_STATUS);
|
||||
@ -1183,9 +1184,12 @@ void xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p)
|
||||
i, xe_mmio_read32(>->mmio, SOFT_SCRATCH(i)));
|
||||
}
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
|
||||
xe_guc_ct_print(&guc->ct, p);
|
||||
drm_puts(p, "\n");
|
||||
xe_guc_ct_print(&guc->ct, p, false);
|
||||
|
||||
drm_puts(p, "\n");
|
||||
xe_guc_submit_print(guc, p);
|
||||
}
|
||||
|
||||
|
@ -359,6 +359,11 @@ static void guc_waklv_init(struct xe_guc_ads *ads)
|
||||
GUC_WORKAROUND_KLV_ID_DISABLE_MTP_DURING_ASYNC_COMPUTE,
|
||||
&offset, &remain);
|
||||
|
||||
if (XE_WA(gt, 14022866841))
|
||||
guc_waklv_enable_simple(ads,
|
||||
GUC_WA_KLV_WAKE_POWER_DOMAINS_FOR_OUTBOUND_MMIO,
|
||||
&offset, &remain);
|
||||
|
||||
/*
|
||||
* On RC6 exit, GuC will write register 0xB04 with the default value provided. As of now,
|
||||
* the default value for this register is determined to be 0xC40. This could change in the
|
||||
|
@ -1590,6 +1590,9 @@ xe_engine_manual_capture(struct xe_hw_engine *hwe, struct xe_hw_engine_snapshot
|
||||
u16 guc_id = 0;
|
||||
u32 lrca = 0;
|
||||
|
||||
if (IS_SRIOV_VF(xe))
|
||||
return;
|
||||
|
||||
new = guc_capture_get_prealloc_node(guc);
|
||||
if (!new)
|
||||
return;
|
||||
@ -1820,7 +1823,7 @@ xe_guc_capture_get_matching_and_lock(struct xe_sched_job *job)
|
||||
return NULL;
|
||||
|
||||
xe = gt_to_xe(q->gt);
|
||||
if (xe->wedged.mode >= 2 || !xe_device_uc_enabled(xe))
|
||||
if (xe->wedged.mode >= 2 || !xe_device_uc_enabled(xe) || IS_SRIOV_VF(xe))
|
||||
return NULL;
|
||||
|
||||
ss = &xe->devcoredump.snapshot;
|
||||
@ -1876,6 +1879,9 @@ xe_engine_snapshot_capture_for_job(struct xe_sched_job *job)
|
||||
enum xe_hw_engine_id id;
|
||||
u32 adj_logical_mask = q->logical_mask;
|
||||
|
||||
if (IS_SRIOV_VF(xe))
|
||||
return;
|
||||
|
||||
for_each_hw_engine(hwe, q->gt, id) {
|
||||
if (hwe->class != q->hwe->class ||
|
||||
!(BIT(hwe->logical_instance) & adj_logical_mask)) {
|
||||
|
@ -213,7 +213,7 @@ int xe_guc_ct_init(struct xe_guc_ct *ct)
|
||||
|
||||
xe_gt_assert(gt, !(guc_ct_size() % PAGE_SIZE));
|
||||
|
||||
ct->g2h_wq = alloc_ordered_workqueue("xe-g2h-wq", 0);
|
||||
ct->g2h_wq = alloc_ordered_workqueue("xe-g2h-wq", WQ_MEM_RECLAIM);
|
||||
if (!ct->g2h_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1607,7 +1607,8 @@ static void g2h_worker_func(struct work_struct *w)
|
||||
receive_g2h(ct);
|
||||
}
|
||||
|
||||
struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_alloc(struct xe_guc_ct *ct, bool atomic)
|
||||
static struct xe_guc_ct_snapshot *guc_ct_snapshot_alloc(struct xe_guc_ct *ct, bool atomic,
|
||||
bool want_ctb)
|
||||
{
|
||||
struct xe_guc_ct_snapshot *snapshot;
|
||||
|
||||
@ -1615,7 +1616,7 @@ struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_alloc(struct xe_guc_ct *ct, bool a
|
||||
if (!snapshot)
|
||||
return NULL;
|
||||
|
||||
if (ct->bo) {
|
||||
if (ct->bo && want_ctb) {
|
||||
snapshot->ctb_size = ct->bo->size;
|
||||
snapshot->ctb = kmalloc(snapshot->ctb_size, atomic ? GFP_ATOMIC : GFP_KERNEL);
|
||||
}
|
||||
@ -1645,25 +1646,13 @@ static void guc_ctb_snapshot_print(struct guc_ctb_snapshot *snapshot,
|
||||
drm_printf(p, "\tstatus (memory): 0x%x\n", snapshot->desc.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_guc_ct_snapshot_capture - Take a quick snapshot of the CT state.
|
||||
* @ct: GuC CT object.
|
||||
* @atomic: Boolean to indicate if this is called from atomic context like
|
||||
* reset or CTB handler or from some regular path like debugfs.
|
||||
*
|
||||
* This can be printed out in a later stage like during dev_coredump
|
||||
* analysis.
|
||||
*
|
||||
* Returns: a GuC CT snapshot object that must be freed by the caller
|
||||
* by using `xe_guc_ct_snapshot_free`.
|
||||
*/
|
||||
struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct,
|
||||
bool atomic)
|
||||
static struct xe_guc_ct_snapshot *guc_ct_snapshot_capture(struct xe_guc_ct *ct, bool atomic,
|
||||
bool want_ctb)
|
||||
{
|
||||
struct xe_device *xe = ct_to_xe(ct);
|
||||
struct xe_guc_ct_snapshot *snapshot;
|
||||
|
||||
snapshot = xe_guc_ct_snapshot_alloc(ct, atomic);
|
||||
snapshot = guc_ct_snapshot_alloc(ct, atomic, want_ctb);
|
||||
if (!snapshot) {
|
||||
xe_gt_err(ct_to_gt(ct), "Skipping CTB snapshot entirely.\n");
|
||||
return NULL;
|
||||
@ -1682,6 +1671,21 @@ struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct,
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_guc_ct_snapshot_capture - Take a quick snapshot of the CT state.
|
||||
* @ct: GuC CT object.
|
||||
*
|
||||
* This can be printed out in a later stage like during dev_coredump
|
||||
* analysis. This is safe to be called during atomic context.
|
||||
*
|
||||
* Returns: a GuC CT snapshot object that must be freed by the caller
|
||||
* by using `xe_guc_ct_snapshot_free`.
|
||||
*/
|
||||
struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct)
|
||||
{
|
||||
return guc_ct_snapshot_capture(ct, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_guc_ct_snapshot_print - Print out a given GuC CT snapshot.
|
||||
* @snapshot: GuC CT snapshot object.
|
||||
@ -1704,12 +1708,8 @@ void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot,
|
||||
drm_printf(p, "\tg2h outstanding: %d\n",
|
||||
snapshot->g2h_outstanding);
|
||||
|
||||
if (snapshot->ctb) {
|
||||
if (snapshot->ctb)
|
||||
xe_print_blob_ascii85(p, "CTB data", snapshot->ctb, 0, snapshot->ctb_size);
|
||||
} else {
|
||||
drm_printf(p, "CTB snapshot missing!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
drm_puts(p, "CT disabled\n");
|
||||
}
|
||||
@ -1735,14 +1735,16 @@ void xe_guc_ct_snapshot_free(struct xe_guc_ct_snapshot *snapshot)
|
||||
* xe_guc_ct_print - GuC CT Print.
|
||||
* @ct: GuC CT.
|
||||
* @p: drm_printer where it will be printed out.
|
||||
* @want_ctb: Should the full CTB content be dumped (vs just the headers)
|
||||
*
|
||||
* This function quickly capture a snapshot and immediately print it out.
|
||||
* This function will quickly capture a snapshot of the CT state
|
||||
* and immediately print it out.
|
||||
*/
|
||||
void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p)
|
||||
void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool want_ctb)
|
||||
{
|
||||
struct xe_guc_ct_snapshot *snapshot;
|
||||
|
||||
snapshot = xe_guc_ct_snapshot_capture(ct, false);
|
||||
snapshot = guc_ct_snapshot_capture(ct, false, want_ctb);
|
||||
xe_guc_ct_snapshot_print(snapshot, p);
|
||||
xe_guc_ct_snapshot_free(snapshot);
|
||||
}
|
||||
@ -1776,7 +1778,7 @@ static void ct_dead_capture(struct xe_guc_ct *ct, struct guc_ctb *ctb, u32 reaso
|
||||
return;
|
||||
|
||||
snapshot_log = xe_guc_log_snapshot_capture(&guc->log, true);
|
||||
snapshot_ct = xe_guc_ct_snapshot_capture((ct), true);
|
||||
snapshot_ct = xe_guc_ct_snapshot_capture((ct));
|
||||
|
||||
spin_lock_irqsave(&ct->dead.lock, flags);
|
||||
|
||||
|
@ -17,11 +17,10 @@ void xe_guc_ct_disable(struct xe_guc_ct *ct);
|
||||
void xe_guc_ct_stop(struct xe_guc_ct *ct);
|
||||
void xe_guc_ct_fast_path(struct xe_guc_ct *ct);
|
||||
|
||||
struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_alloc(struct xe_guc_ct *ct, bool atomic);
|
||||
struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct, bool atomic);
|
||||
struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct);
|
||||
void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, struct drm_printer *p);
|
||||
void xe_guc_ct_snapshot_free(struct xe_guc_ct_snapshot *snapshot);
|
||||
void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p);
|
||||
void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool want_ctb);
|
||||
|
||||
static inline bool xe_guc_ct_enabled(struct xe_guc_ct *ct)
|
||||
{
|
||||
|
@ -47,9 +47,23 @@ static int guc_log(struct seq_file *m, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int guc_ctb(struct seq_file *m, void *data)
|
||||
{
|
||||
struct xe_guc *guc = node_to_guc(m->private);
|
||||
struct xe_device *xe = guc_to_xe(guc);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
|
||||
xe_pm_runtime_get(xe);
|
||||
xe_guc_ct_print(&guc->ct, &p, true);
|
||||
xe_pm_runtime_put(xe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_info_list debugfs_list[] = {
|
||||
{"guc_info", guc_info, 0},
|
||||
{"guc_log", guc_log, 0},
|
||||
{"guc_ctb", guc_ctb, 0},
|
||||
};
|
||||
|
||||
void xe_guc_debugfs_register(struct xe_guc *guc, struct dentry *parent)
|
||||
|
@ -105,6 +105,7 @@ struct guc_update_exec_queue_policy {
|
||||
|
||||
#define GUC_CTL_FEATURE 2
|
||||
#define GUC_CTL_ENABLE_SLPC BIT(2)
|
||||
#define GUC_CTL_ENABLE_LITE_RESTORE BIT(4)
|
||||
#define GUC_CTL_DISABLE_SCHEDULER BIT(14)
|
||||
|
||||
#define GUC_CTL_DEBUG 3
|
||||
|
@ -145,8 +145,9 @@ struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log,
|
||||
struct xe_device *xe = log_to_xe(log);
|
||||
struct xe_guc *guc = log_to_guc(log);
|
||||
struct xe_gt *gt = log_to_gt(log);
|
||||
unsigned int fw_ref;
|
||||
size_t remain;
|
||||
int i, err;
|
||||
int i;
|
||||
|
||||
if (!log->bo) {
|
||||
xe_gt_err(gt, "GuC log buffer not allocated\n");
|
||||
@ -168,12 +169,12 @@ struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log,
|
||||
remain -= size;
|
||||
}
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err) {
|
||||
snapshot->stamp = ~0;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref) {
|
||||
snapshot->stamp = ~0ULL;
|
||||
} else {
|
||||
snapshot->stamp = xe_mmio_read32(>->mmio, GUC_PMTIMESTAMP);
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
snapshot->stamp = xe_mmio_read64_2x32(>->mmio, GUC_PMTIMESTAMP_LO);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
snapshot->ktime = ktime_get_boottime_ns();
|
||||
snapshot->level = log->level;
|
||||
@ -204,7 +205,7 @@ void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_
|
||||
snapshot->ver_found.major, snapshot->ver_found.minor, snapshot->ver_found.patch,
|
||||
snapshot->ver_want.major, snapshot->ver_want.minor, snapshot->ver_want.patch);
|
||||
drm_printf(p, "Kernel timestamp: 0x%08llX [%llu]\n", snapshot->ktime, snapshot->ktime);
|
||||
drm_printf(p, "GuC timestamp: 0x%08X [%u]\n", snapshot->stamp, snapshot->stamp);
|
||||
drm_printf(p, "GuC timestamp: 0x%08llX [%llu]\n", snapshot->stamp, snapshot->stamp);
|
||||
drm_printf(p, "Log level: %u\n", snapshot->level);
|
||||
|
||||
remain = snapshot->size;
|
||||
|
@ -27,7 +27,7 @@ struct xe_guc_log_snapshot {
|
||||
/** @ktime: Kernel time the snapshot was taken */
|
||||
u64 ktime;
|
||||
/** @stamp: GuC timestamp at which the snapshot was taken */
|
||||
u32 stamp;
|
||||
u64 stamp;
|
||||
/** @level: GuC log verbosity level */
|
||||
u32 level;
|
||||
/** @ver_found: GuC firmware version */
|
||||
|
@ -415,22 +415,24 @@ u32 xe_guc_pc_get_act_freq(struct xe_guc_pc *pc)
|
||||
int xe_guc_pc_get_cur_freq(struct xe_guc_pc *pc, u32 *freq)
|
||||
{
|
||||
struct xe_gt *gt = pc_to_gt(pc);
|
||||
int ret;
|
||||
unsigned int fw_ref;
|
||||
|
||||
/*
|
||||
* GuC SLPC plays with cur freq request when GuCRC is enabled
|
||||
* Block RC6 for a more reliable read.
|
||||
*/
|
||||
ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (ret)
|
||||
return ret;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
*freq = xe_mmio_read32(>->mmio, RPNSWREQ);
|
||||
|
||||
*freq = REG_FIELD_GET(REQ_RATIO_MASK, *freq);
|
||||
*freq = decode_freq(*freq);
|
||||
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -480,6 +482,7 @@ u32 xe_guc_pc_get_rpn_freq(struct xe_guc_pc *pc)
|
||||
int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq)
|
||||
{
|
||||
struct xe_gt *gt = pc_to_gt(pc);
|
||||
unsigned int fw_ref;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&pc->freq_lock);
|
||||
@ -493,9 +496,11 @@ int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq)
|
||||
* GuC SLPC plays with min freq request when GuCRC is enabled
|
||||
* Block RC6 for a more reliable read.
|
||||
*/
|
||||
ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (ret)
|
||||
goto out;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto fw;
|
||||
}
|
||||
|
||||
ret = pc_action_query_task_state(pc);
|
||||
if (ret)
|
||||
@ -504,7 +509,7 @@ int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq)
|
||||
*freq = pc_get_min_freq(pc);
|
||||
|
||||
fw:
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
out:
|
||||
mutex_unlock(&pc->freq_lock);
|
||||
return ret;
|
||||
@ -855,6 +860,7 @@ int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc)
|
||||
{
|
||||
struct xe_device *xe = pc_to_xe(pc);
|
||||
struct xe_gt *gt = pc_to_gt(pc);
|
||||
unsigned int fw_ref;
|
||||
int ret = 0;
|
||||
|
||||
if (xe->info.skip_guc_pc)
|
||||
@ -864,13 +870,15 @@ int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (ret)
|
||||
return ret;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
xe_gt_idle_disable_c6(gt);
|
||||
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -956,13 +964,16 @@ int xe_guc_pc_start(struct xe_guc_pc *pc)
|
||||
struct xe_device *xe = pc_to_xe(pc);
|
||||
struct xe_gt *gt = pc_to_gt(pc);
|
||||
u32 size = PAGE_ALIGN(sizeof(struct slpc_shared_data));
|
||||
unsigned int fw_ref;
|
||||
int ret;
|
||||
|
||||
xe_gt_assert(gt, xe_device_uc_enabled(xe));
|
||||
|
||||
ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (ret)
|
||||
return ret;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (xe->info.skip_guc_pc) {
|
||||
if (xe->info.platform != XE_PVC)
|
||||
@ -1005,7 +1016,7 @@ int xe_guc_pc_start(struct xe_guc_pc *pc)
|
||||
ret = pc_action_setup_gucrc(pc, GUCRC_FIRMWARE_CONTROL);
|
||||
|
||||
out:
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1037,18 +1048,19 @@ static void xe_guc_pc_fini_hw(void *arg)
|
||||
{
|
||||
struct xe_guc_pc *pc = arg;
|
||||
struct xe_device *xe = pc_to_xe(pc);
|
||||
unsigned int fw_ref;
|
||||
|
||||
if (xe_device_wedged(xe))
|
||||
return;
|
||||
|
||||
XE_WARN_ON(xe_force_wake_get(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL);
|
||||
xe_guc_pc_gucrc_disable(pc);
|
||||
XE_WARN_ON(xe_guc_pc_stop(pc));
|
||||
|
||||
/* Bind requested freq to mert_freq_cap before unload */
|
||||
pc_set_cur_freq(pc, min(pc_max_freq_cap(pc), pc->rpe_freq));
|
||||
|
||||
xe_force_wake_put(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(pc_to_gt(pc)), fw_ref);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -717,6 +717,7 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job)
|
||||
struct xe_exec_queue *q = job->q;
|
||||
struct xe_guc *guc = exec_queue_to_guc(q);
|
||||
struct xe_device *xe = guc_to_xe(guc);
|
||||
struct dma_fence *fence = NULL;
|
||||
bool lr = xe_exec_queue_is_lr(q);
|
||||
|
||||
xe_assert(xe, !(exec_queue_destroyed(q) || exec_queue_pending_disable(q)) ||
|
||||
@ -734,12 +735,12 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job)
|
||||
|
||||
if (lr) {
|
||||
xe_sched_job_set_error(job, -EOPNOTSUPP);
|
||||
return NULL;
|
||||
} else if (test_and_set_bit(JOB_FLAG_SUBMIT, &job->fence->flags)) {
|
||||
return job->fence;
|
||||
dma_fence_put(job->fence); /* Drop ref from xe_sched_job_arm */
|
||||
} else {
|
||||
return dma_fence_get(job->fence);
|
||||
fence = job->fence;
|
||||
}
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
static void guc_exec_queue_free_job(struct drm_sched_job *drm_job)
|
||||
@ -1035,6 +1036,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
|
||||
struct xe_guc *guc = exec_queue_to_guc(q);
|
||||
const char *process_name = "no process";
|
||||
struct xe_device *xe = guc_to_xe(guc);
|
||||
unsigned int fw_ref;
|
||||
int err = -ETIME;
|
||||
pid_t pid = -1;
|
||||
int i = 0;
|
||||
@ -1068,12 +1070,13 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
|
||||
if (!exec_queue_killed(q) && !xe->devcoredump.captured &&
|
||||
!xe_guc_capture_get_matching_and_lock(job)) {
|
||||
/* take force wake before engine register manual capture */
|
||||
if (xe_force_wake_get(gt_to_fw(q->gt), XE_FORCEWAKE_ALL))
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(q->gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
xe_gt_info(q->gt, "failed to get forcewake for coredump capture\n");
|
||||
|
||||
xe_engine_snapshot_capture_for_job(job);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(q->gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(q->gt), fw_ref);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -296,19 +296,19 @@ void xe_huc_sanitize(struct xe_huc *huc)
|
||||
void xe_huc_print_info(struct xe_huc *huc, struct drm_printer *p)
|
||||
{
|
||||
struct xe_gt *gt = huc_to_gt(huc);
|
||||
int err;
|
||||
unsigned int fw_ref;
|
||||
|
||||
xe_uc_fw_print(&huc->fw, p);
|
||||
|
||||
if (!xe_uc_fw_is_enabled(&huc->fw))
|
||||
return;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
drm_printf(p, "\nHuC status: 0x%08x\n",
|
||||
xe_mmio_read32(>->mmio, HUC_KERNEL_LOAD_INFO));
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
@ -774,25 +774,21 @@ void xe_mocs_init(struct xe_gt *gt)
|
||||
|
||||
void xe_mocs_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
struct xe_mocs_info table;
|
||||
unsigned int flags;
|
||||
u32 ret;
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
struct xe_mocs_info table;
|
||||
unsigned int fw_ref, flags;
|
||||
|
||||
flags = get_mocs_settings(xe, &table);
|
||||
|
||||
xe_pm_runtime_get_noresume(xe);
|
||||
ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
|
||||
if (ret)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
goto err_fw;
|
||||
|
||||
table.ops->dump(&table, flags, gt, p);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
err_fw:
|
||||
xe_assert(xe, !ret);
|
||||
xe_pm_runtime_put(xe);
|
||||
}
|
||||
|
||||
|
@ -36,11 +36,22 @@
|
||||
#include "xe_pm.h"
|
||||
#include "xe_sched_job.h"
|
||||
#include "xe_sriov.h"
|
||||
#include "xe_sync.h"
|
||||
|
||||
#define DEFAULT_POLL_FREQUENCY_HZ 200
|
||||
#define DEFAULT_POLL_PERIOD_NS (NSEC_PER_SEC / DEFAULT_POLL_FREQUENCY_HZ)
|
||||
#define XE_OA_UNIT_INVALID U32_MAX
|
||||
|
||||
enum xe_oa_submit_deps {
|
||||
XE_OA_SUBMIT_NO_DEPS,
|
||||
XE_OA_SUBMIT_ADD_DEPS,
|
||||
};
|
||||
|
||||
enum xe_oa_user_extn_from {
|
||||
XE_OA_USER_EXTN_FROM_OPEN,
|
||||
XE_OA_USER_EXTN_FROM_CONFIG,
|
||||
};
|
||||
|
||||
struct xe_oa_reg {
|
||||
struct xe_reg addr;
|
||||
u32 value;
|
||||
@ -70,6 +81,7 @@ struct flex {
|
||||
};
|
||||
|
||||
struct xe_oa_open_param {
|
||||
struct xe_file *xef;
|
||||
u32 oa_unit_id;
|
||||
bool sample;
|
||||
u32 metric_set;
|
||||
@ -81,6 +93,9 @@ struct xe_oa_open_param {
|
||||
struct xe_exec_queue *exec_q;
|
||||
struct xe_hw_engine *hwe;
|
||||
bool no_preempt;
|
||||
struct drm_xe_sync __user *syncs_user;
|
||||
int num_syncs;
|
||||
struct xe_sync_entry *syncs;
|
||||
};
|
||||
|
||||
struct xe_oa_config_bo {
|
||||
@ -90,6 +105,17 @@ struct xe_oa_config_bo {
|
||||
struct xe_bb *bb;
|
||||
};
|
||||
|
||||
struct xe_oa_fence {
|
||||
/* @base: dma fence base */
|
||||
struct dma_fence base;
|
||||
/* @lock: lock for the fence */
|
||||
spinlock_t lock;
|
||||
/* @work: work to signal @base */
|
||||
struct delayed_work work;
|
||||
/* @cb: callback to schedule @work */
|
||||
struct dma_fence_cb cb;
|
||||
};
|
||||
|
||||
#define DRM_FMT(x) DRM_XE_OA_FMT_TYPE_##x
|
||||
|
||||
static const struct xe_oa_format oa_formats[] = {
|
||||
@ -162,10 +188,10 @@ static struct xe_oa_config *xe_oa_get_oa_config(struct xe_oa *oa, int metrics_se
|
||||
return oa_config;
|
||||
}
|
||||
|
||||
static void free_oa_config_bo(struct xe_oa_config_bo *oa_bo)
|
||||
static void free_oa_config_bo(struct xe_oa_config_bo *oa_bo, struct dma_fence *last_fence)
|
||||
{
|
||||
xe_oa_config_put(oa_bo->oa_config);
|
||||
xe_bb_free(oa_bo->bb, NULL);
|
||||
xe_bb_free(oa_bo->bb, last_fence);
|
||||
kfree(oa_bo);
|
||||
}
|
||||
|
||||
@ -570,11 +596,11 @@ static __poll_t xe_oa_poll(struct file *file, poll_table *wait)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xe_oa_submit_bb(struct xe_oa_stream *stream, struct xe_bb *bb)
|
||||
static struct dma_fence *xe_oa_submit_bb(struct xe_oa_stream *stream, enum xe_oa_submit_deps deps,
|
||||
struct xe_bb *bb)
|
||||
{
|
||||
struct xe_sched_job *job;
|
||||
struct dma_fence *fence;
|
||||
long timeout;
|
||||
int err = 0;
|
||||
|
||||
/* Kernel configuration is issued on stream->k_exec_q, not stream->exec_q */
|
||||
@ -584,18 +610,24 @@ static int xe_oa_submit_bb(struct xe_oa_stream *stream, struct xe_bb *bb)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (deps == XE_OA_SUBMIT_ADD_DEPS) {
|
||||
for (int i = 0; i < stream->num_syncs && !err; i++)
|
||||
err = xe_sync_entry_add_deps(&stream->syncs[i], job);
|
||||
if (err) {
|
||||
drm_dbg(&stream->oa->xe->drm, "xe_sync_entry_add_deps err %d\n", err);
|
||||
goto err_put_job;
|
||||
}
|
||||
}
|
||||
|
||||
xe_sched_job_arm(job);
|
||||
fence = dma_fence_get(&job->drm.s_fence->finished);
|
||||
xe_sched_job_push(job);
|
||||
|
||||
timeout = dma_fence_wait_timeout(fence, false, HZ);
|
||||
dma_fence_put(fence);
|
||||
if (timeout < 0)
|
||||
err = timeout;
|
||||
else if (!timeout)
|
||||
err = -ETIME;
|
||||
return fence;
|
||||
err_put_job:
|
||||
xe_sched_job_put(job);
|
||||
exit:
|
||||
return err;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static void write_cs_mi_lri(struct xe_bb *bb, const struct xe_oa_reg *reg_data, u32 n_regs)
|
||||
@ -639,7 +671,8 @@ static void xe_oa_free_configs(struct xe_oa_stream *stream)
|
||||
|
||||
xe_oa_config_put(stream->oa_config);
|
||||
llist_for_each_entry_safe(oa_bo, tmp, stream->oa_config_bos.first, node)
|
||||
free_oa_config_bo(oa_bo);
|
||||
free_oa_config_bo(oa_bo, stream->last_fence);
|
||||
dma_fence_put(stream->last_fence);
|
||||
}
|
||||
|
||||
static void xe_oa_store_flex(struct xe_oa_stream *stream, struct xe_lrc *lrc,
|
||||
@ -659,6 +692,7 @@ static void xe_oa_store_flex(struct xe_oa_stream *stream, struct xe_lrc *lrc,
|
||||
static int xe_oa_modify_ctx_image(struct xe_oa_stream *stream, struct xe_lrc *lrc,
|
||||
const struct flex *flex, u32 count)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
struct xe_bb *bb;
|
||||
int err;
|
||||
|
||||
@ -670,7 +704,16 @@ static int xe_oa_modify_ctx_image(struct xe_oa_stream *stream, struct xe_lrc *lr
|
||||
|
||||
xe_oa_store_flex(stream, lrc, bb, flex, count);
|
||||
|
||||
err = xe_oa_submit_bb(stream, bb);
|
||||
fence = xe_oa_submit_bb(stream, XE_OA_SUBMIT_NO_DEPS, bb);
|
||||
if (IS_ERR(fence)) {
|
||||
err = PTR_ERR(fence);
|
||||
goto free_bb;
|
||||
}
|
||||
xe_bb_free(bb, fence);
|
||||
dma_fence_put(fence);
|
||||
|
||||
return 0;
|
||||
free_bb:
|
||||
xe_bb_free(bb, NULL);
|
||||
exit:
|
||||
return err;
|
||||
@ -678,6 +721,7 @@ exit:
|
||||
|
||||
static int xe_oa_load_with_lri(struct xe_oa_stream *stream, struct xe_oa_reg *reg_lri)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
struct xe_bb *bb;
|
||||
int err;
|
||||
|
||||
@ -689,7 +733,16 @@ static int xe_oa_load_with_lri(struct xe_oa_stream *stream, struct xe_oa_reg *re
|
||||
|
||||
write_cs_mi_lri(bb, reg_lri, 1);
|
||||
|
||||
err = xe_oa_submit_bb(stream, bb);
|
||||
fence = xe_oa_submit_bb(stream, XE_OA_SUBMIT_NO_DEPS, bb);
|
||||
if (IS_ERR(fence)) {
|
||||
err = PTR_ERR(fence);
|
||||
goto free_bb;
|
||||
}
|
||||
xe_bb_free(bb, fence);
|
||||
dma_fence_put(fence);
|
||||
|
||||
return 0;
|
||||
free_bb:
|
||||
xe_bb_free(bb, NULL);
|
||||
exit:
|
||||
return err;
|
||||
@ -837,7 +890,7 @@ static void xe_oa_stream_destroy(struct xe_oa_stream *stream)
|
||||
|
||||
xe_oa_free_oa_buffer(stream);
|
||||
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
xe_pm_runtime_put(stream->oa->xe);
|
||||
|
||||
/* Wa_1509372804:pvc: Unset the override of GUCRC mode to enable rc6 */
|
||||
@ -845,6 +898,7 @@ static void xe_oa_stream_destroy(struct xe_oa_stream *stream)
|
||||
xe_gt_WARN_ON(gt, xe_guc_pc_unset_gucrc_mode(>->uc.guc.pc));
|
||||
|
||||
xe_oa_free_configs(stream);
|
||||
xe_file_put(stream->xef);
|
||||
}
|
||||
|
||||
static int xe_oa_alloc_oa_buffer(struct xe_oa_stream *stream)
|
||||
@ -915,11 +969,62 @@ out:
|
||||
return oa_bo;
|
||||
}
|
||||
|
||||
static void xe_oa_update_last_fence(struct xe_oa_stream *stream, struct dma_fence *fence)
|
||||
{
|
||||
dma_fence_put(stream->last_fence);
|
||||
stream->last_fence = dma_fence_get(fence);
|
||||
}
|
||||
|
||||
static void xe_oa_fence_work_fn(struct work_struct *w)
|
||||
{
|
||||
struct xe_oa_fence *ofence = container_of(w, typeof(*ofence), work.work);
|
||||
|
||||
/* Signal fence to indicate new OA configuration is active */
|
||||
dma_fence_signal(&ofence->base);
|
||||
dma_fence_put(&ofence->base);
|
||||
}
|
||||
|
||||
static void xe_oa_config_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
|
||||
{
|
||||
/* Additional empirical delay needed for NOA programming after registers are written */
|
||||
#define NOA_PROGRAM_ADDITIONAL_DELAY_US 500
|
||||
|
||||
struct xe_oa_fence *ofence = container_of(cb, typeof(*ofence), cb);
|
||||
|
||||
INIT_DELAYED_WORK(&ofence->work, xe_oa_fence_work_fn);
|
||||
queue_delayed_work(system_unbound_wq, &ofence->work,
|
||||
usecs_to_jiffies(NOA_PROGRAM_ADDITIONAL_DELAY_US));
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
|
||||
static const char *xe_oa_get_driver_name(struct dma_fence *fence)
|
||||
{
|
||||
return "xe_oa";
|
||||
}
|
||||
|
||||
static const char *xe_oa_get_timeline_name(struct dma_fence *fence)
|
||||
{
|
||||
return "unbound";
|
||||
}
|
||||
|
||||
static const struct dma_fence_ops xe_oa_fence_ops = {
|
||||
.get_driver_name = xe_oa_get_driver_name,
|
||||
.get_timeline_name = xe_oa_get_timeline_name,
|
||||
};
|
||||
|
||||
static int xe_oa_emit_oa_config(struct xe_oa_stream *stream, struct xe_oa_config *config)
|
||||
{
|
||||
#define NOA_PROGRAM_ADDITIONAL_DELAY_US 500
|
||||
struct xe_oa_config_bo *oa_bo;
|
||||
int err, us = NOA_PROGRAM_ADDITIONAL_DELAY_US;
|
||||
struct xe_oa_fence *ofence;
|
||||
int i, err, num_signal = 0;
|
||||
struct dma_fence *fence;
|
||||
|
||||
ofence = kzalloc(sizeof(*ofence), GFP_KERNEL);
|
||||
if (!ofence) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
oa_bo = xe_oa_alloc_config_buffer(stream, config);
|
||||
if (IS_ERR(oa_bo)) {
|
||||
@ -927,11 +1032,50 @@ static int xe_oa_emit_oa_config(struct xe_oa_stream *stream, struct xe_oa_config
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = xe_oa_submit_bb(stream, oa_bo->bb);
|
||||
/* Emit OA configuration batch */
|
||||
fence = xe_oa_submit_bb(stream, XE_OA_SUBMIT_ADD_DEPS, oa_bo->bb);
|
||||
if (IS_ERR(fence)) {
|
||||
err = PTR_ERR(fence);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Additional empirical delay needed for NOA programming after registers are written */
|
||||
usleep_range(us, 2 * us);
|
||||
/* Point of no return: initialize and set fence to signal */
|
||||
spin_lock_init(&ofence->lock);
|
||||
dma_fence_init(&ofence->base, &xe_oa_fence_ops, &ofence->lock, 0, 0);
|
||||
|
||||
for (i = 0; i < stream->num_syncs; i++) {
|
||||
if (stream->syncs[i].flags & DRM_XE_SYNC_FLAG_SIGNAL)
|
||||
num_signal++;
|
||||
xe_sync_entry_signal(&stream->syncs[i], &ofence->base);
|
||||
}
|
||||
|
||||
/* Additional dma_fence_get in case we dma_fence_wait */
|
||||
if (!num_signal)
|
||||
dma_fence_get(&ofence->base);
|
||||
|
||||
/* Update last fence too before adding callback */
|
||||
xe_oa_update_last_fence(stream, fence);
|
||||
|
||||
/* Add job fence callback to schedule work to signal ofence->base */
|
||||
err = dma_fence_add_callback(fence, &ofence->cb, xe_oa_config_cb);
|
||||
xe_gt_assert(stream->gt, !err || err == -ENOENT);
|
||||
if (err == -ENOENT)
|
||||
xe_oa_config_cb(fence, &ofence->cb);
|
||||
|
||||
/* If nothing needs to be signaled we wait synchronously */
|
||||
if (!num_signal) {
|
||||
dma_fence_wait(&ofence->base, false);
|
||||
dma_fence_put(&ofence->base);
|
||||
}
|
||||
|
||||
/* Done with syncs */
|
||||
for (i = 0; i < stream->num_syncs; i++)
|
||||
xe_sync_entry_cleanup(&stream->syncs[i]);
|
||||
kfree(stream->syncs);
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
kfree(ofence);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1003,6 +1147,262 @@ static int xe_oa_enable_metric_set(struct xe_oa_stream *stream)
|
||||
return xe_oa_emit_oa_config(stream, stream->oa_config);
|
||||
}
|
||||
|
||||
static int decode_oa_format(struct xe_oa *oa, u64 fmt, enum xe_oa_format_name *name)
|
||||
{
|
||||
u32 counter_size = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE, fmt);
|
||||
u32 counter_sel = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SEL, fmt);
|
||||
u32 bc_report = FIELD_GET(DRM_XE_OA_FORMAT_MASK_BC_REPORT, fmt);
|
||||
u32 type = FIELD_GET(DRM_XE_OA_FORMAT_MASK_FMT_TYPE, fmt);
|
||||
int idx;
|
||||
|
||||
for_each_set_bit(idx, oa->format_mask, __XE_OA_FORMAT_MAX) {
|
||||
const struct xe_oa_format *f = &oa->oa_formats[idx];
|
||||
|
||||
if (counter_size == f->counter_size && bc_report == f->bc_report &&
|
||||
type == f->type && counter_sel == f->counter_select) {
|
||||
*name = idx;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_unit_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
if (value >= oa->oa_unit_ids) {
|
||||
drm_dbg(&oa->xe->drm, "OA unit ID out of range %lld\n", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->oa_unit_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_sample_oa(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->sample = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_metric_set(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->metric_set = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_format(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
int ret = decode_oa_format(oa, value, ¶m->oa_format);
|
||||
|
||||
if (ret) {
|
||||
drm_dbg(&oa->xe->drm, "Unsupported OA report format %#llx\n", value);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_exponent(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
#define OA_EXPONENT_MAX 31
|
||||
|
||||
if (value > OA_EXPONENT_MAX) {
|
||||
drm_dbg(&oa->xe->drm, "OA timer exponent too high (> %u)\n", OA_EXPONENT_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->period_exponent = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_disabled(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->disabled = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_exec_queue_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->exec_queue_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_engine_instance(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->engine_instance = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_no_preempt(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->no_preempt = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_num_syncs(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->num_syncs = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_syncs_user(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->syncs_user = u64_to_user_ptr(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_ret_inval(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_set_property_fn)(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param);
|
||||
static const xe_oa_set_property_fn xe_oa_set_property_funcs_open[] = {
|
||||
[DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_oa_unit_id,
|
||||
[DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_sample_oa,
|
||||
[DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set,
|
||||
[DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_oa_format,
|
||||
[DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_oa_exponent,
|
||||
[DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_disabled,
|
||||
[DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_exec_queue_id,
|
||||
[DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_engine_instance,
|
||||
[DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_no_preempt,
|
||||
[DRM_XE_OA_PROPERTY_NUM_SYNCS] = xe_oa_set_prop_num_syncs,
|
||||
[DRM_XE_OA_PROPERTY_SYNCS] = xe_oa_set_prop_syncs_user,
|
||||
};
|
||||
|
||||
static const xe_oa_set_property_fn xe_oa_set_property_funcs_config[] = {
|
||||
[DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set,
|
||||
[DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_prop_ret_inval,
|
||||
[DRM_XE_OA_PROPERTY_NUM_SYNCS] = xe_oa_set_prop_num_syncs,
|
||||
[DRM_XE_OA_PROPERTY_SYNCS] = xe_oa_set_prop_syncs_user,
|
||||
};
|
||||
|
||||
static int xe_oa_user_ext_set_property(struct xe_oa *oa, enum xe_oa_user_extn_from from,
|
||||
u64 extension, struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_ext_set_property ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(xe_oa_set_property_funcs_open) !=
|
||||
ARRAY_SIZE(xe_oa_set_property_funcs_config));
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.property >= ARRAY_SIZE(xe_oa_set_property_funcs_open)) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.pad))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_oa_set_property_funcs_open));
|
||||
|
||||
if (from == XE_OA_USER_EXTN_FROM_CONFIG)
|
||||
return xe_oa_set_property_funcs_config[idx](oa, ext.value, param);
|
||||
else
|
||||
return xe_oa_set_property_funcs_open[idx](oa, ext.value, param);
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_user_extension_fn)(struct xe_oa *oa, enum xe_oa_user_extn_from from,
|
||||
u64 extension, struct xe_oa_open_param *param);
|
||||
static const xe_oa_user_extension_fn xe_oa_user_extension_funcs[] = {
|
||||
[DRM_XE_OA_EXTENSION_SET_PROPERTY] = xe_oa_user_ext_set_property,
|
||||
};
|
||||
|
||||
#define MAX_USER_EXTENSIONS 16
|
||||
static int xe_oa_user_extensions(struct xe_oa *oa, enum xe_oa_user_extn_from from, u64 extension,
|
||||
int ext_number, struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_user_extension ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext_number >= MAX_USER_EXTENSIONS))
|
||||
return -E2BIG;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.pad) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.name >= ARRAY_SIZE(xe_oa_user_extension_funcs)))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.name, ARRAY_SIZE(xe_oa_user_extension_funcs));
|
||||
err = xe_oa_user_extension_funcs[idx](oa, from, extension, param);
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return err;
|
||||
|
||||
if (ext.next_extension)
|
||||
return xe_oa_user_extensions(oa, from, ext.next_extension, ++ext_number, param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_parse_syncs(struct xe_oa *oa, struct xe_oa_open_param *param)
|
||||
{
|
||||
int ret, num_syncs, num_ufence = 0;
|
||||
|
||||
if (param->num_syncs && !param->syncs_user) {
|
||||
drm_dbg(&oa->xe->drm, "num_syncs specified without sync array\n");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (param->num_syncs) {
|
||||
param->syncs = kcalloc(param->num_syncs, sizeof(*param->syncs), GFP_KERNEL);
|
||||
if (!param->syncs) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
for (num_syncs = 0; num_syncs < param->num_syncs; num_syncs++) {
|
||||
ret = xe_sync_entry_parse(oa->xe, param->xef, ¶m->syncs[num_syncs],
|
||||
¶m->syncs_user[num_syncs], 0);
|
||||
if (ret)
|
||||
goto err_syncs;
|
||||
|
||||
if (xe_sync_is_ufence(¶m->syncs[num_syncs]))
|
||||
num_ufence++;
|
||||
}
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, num_ufence > 1)) {
|
||||
ret = -EINVAL;
|
||||
goto err_syncs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_syncs:
|
||||
while (num_syncs--)
|
||||
xe_sync_entry_cleanup(¶m->syncs[num_syncs]);
|
||||
kfree(param->syncs);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xe_oa_stream_enable(struct xe_oa_stream *stream)
|
||||
{
|
||||
stream->pollin = false;
|
||||
@ -1096,36 +1496,38 @@ static int xe_oa_disable_locked(struct xe_oa_stream *stream)
|
||||
|
||||
static long xe_oa_config_locked(struct xe_oa_stream *stream, u64 arg)
|
||||
{
|
||||
struct drm_xe_ext_set_property ext;
|
||||
struct xe_oa_open_param param = {};
|
||||
long ret = stream->oa_config->id;
|
||||
struct xe_oa_config *config;
|
||||
int err;
|
||||
|
||||
err = __copy_from_user(&ext, u64_to_user_ptr(arg), sizeof(ext));
|
||||
if (XE_IOCTL_DBG(stream->oa->xe, err))
|
||||
return -EFAULT;
|
||||
err = xe_oa_user_extensions(stream->oa, XE_OA_USER_EXTN_FROM_CONFIG, arg, 0, ¶m);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (XE_IOCTL_DBG(stream->oa->xe, ext.pad) ||
|
||||
XE_IOCTL_DBG(stream->oa->xe, ext.base.name != DRM_XE_OA_EXTENSION_SET_PROPERTY) ||
|
||||
XE_IOCTL_DBG(stream->oa->xe, ext.base.next_extension) ||
|
||||
XE_IOCTL_DBG(stream->oa->xe, ext.property != DRM_XE_OA_PROPERTY_OA_METRIC_SET))
|
||||
return -EINVAL;
|
||||
|
||||
config = xe_oa_get_oa_config(stream->oa, ext.value);
|
||||
config = xe_oa_get_oa_config(stream->oa, param.metric_set);
|
||||
if (!config)
|
||||
return -ENODEV;
|
||||
|
||||
if (config != stream->oa_config) {
|
||||
err = xe_oa_emit_oa_config(stream, config);
|
||||
if (!err)
|
||||
config = xchg(&stream->oa_config, config);
|
||||
else
|
||||
ret = err;
|
||||
param.xef = stream->xef;
|
||||
err = xe_oa_parse_syncs(stream->oa, ¶m);
|
||||
if (err)
|
||||
goto err_config_put;
|
||||
|
||||
stream->num_syncs = param.num_syncs;
|
||||
stream->syncs = param.syncs;
|
||||
|
||||
err = xe_oa_emit_oa_config(stream, config);
|
||||
if (!err) {
|
||||
config = xchg(&stream->oa_config, config);
|
||||
drm_dbg(&stream->oa->xe->drm, "changed to oa config uuid=%s\n",
|
||||
stream->oa_config->uuid);
|
||||
}
|
||||
|
||||
err_config_put:
|
||||
xe_oa_config_put(config);
|
||||
|
||||
return ret;
|
||||
return err ?: ret;
|
||||
}
|
||||
|
||||
static long xe_oa_status_locked(struct xe_oa_stream *stream, unsigned long arg)
|
||||
@ -1353,6 +1755,7 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream,
|
||||
{
|
||||
struct xe_oa_unit *u = param->hwe->oa_unit;
|
||||
struct xe_gt *gt = param->hwe->gt;
|
||||
unsigned int fw_ref;
|
||||
int ret;
|
||||
|
||||
stream->exec_q = param->exec_q;
|
||||
@ -1366,6 +1769,10 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream,
|
||||
stream->period_exponent = param->period_exponent;
|
||||
stream->no_preempt = param->no_preempt;
|
||||
|
||||
stream->xef = xe_file_get(param->xef);
|
||||
stream->num_syncs = param->num_syncs;
|
||||
stream->syncs = param->syncs;
|
||||
|
||||
/*
|
||||
* For Xe2+, when overrun mode is enabled, there are no partial reports at the end
|
||||
* of buffer, making the OA buffer effectively a non-power-of-2 size circular
|
||||
@ -1413,7 +1820,11 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream,
|
||||
|
||||
/* Take runtime pm ref and forcewake to disable RC6 */
|
||||
xe_pm_runtime_get(stream->oa->xe);
|
||||
XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_fw_put;
|
||||
}
|
||||
|
||||
ret = xe_oa_alloc_oa_buffer(stream);
|
||||
if (ret)
|
||||
@ -1455,13 +1866,14 @@ err_put_k_exec_q:
|
||||
err_free_oa_buf:
|
||||
xe_oa_free_oa_buffer(stream);
|
||||
err_fw_put:
|
||||
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL));
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_pm_runtime_put(stream->oa->xe);
|
||||
if (stream->override_gucrc)
|
||||
xe_gt_WARN_ON(gt, xe_guc_pc_unset_gucrc_mode(>->uc.guc.pc));
|
||||
err_free_configs:
|
||||
xe_oa_free_configs(stream);
|
||||
exit:
|
||||
xe_file_put(stream->xef);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1571,27 +1983,6 @@ static bool engine_supports_oa_format(const struct xe_hw_engine *hwe, int type)
|
||||
}
|
||||
}
|
||||
|
||||
static int decode_oa_format(struct xe_oa *oa, u64 fmt, enum xe_oa_format_name *name)
|
||||
{
|
||||
u32 counter_size = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE, fmt);
|
||||
u32 counter_sel = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SEL, fmt);
|
||||
u32 bc_report = FIELD_GET(DRM_XE_OA_FORMAT_MASK_BC_REPORT, fmt);
|
||||
u32 type = FIELD_GET(DRM_XE_OA_FORMAT_MASK_FMT_TYPE, fmt);
|
||||
int idx;
|
||||
|
||||
for_each_set_bit(idx, oa->format_mask, __XE_OA_FORMAT_MAX) {
|
||||
const struct xe_oa_format *f = &oa->oa_formats[idx];
|
||||
|
||||
if (counter_size == f->counter_size && bc_report == f->bc_report &&
|
||||
type == f->type && counter_sel == f->counter_select) {
|
||||
*name = idx;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_oa_unit_id - Return OA unit ID for a hardware engine
|
||||
* @hwe: @xe_hw_engine
|
||||
@ -1638,155 +2029,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_unit_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
if (value >= oa->oa_unit_ids) {
|
||||
drm_dbg(&oa->xe->drm, "OA unit ID out of range %lld\n", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->oa_unit_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_sample_oa(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->sample = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_metric_set(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->metric_set = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_format(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
int ret = decode_oa_format(oa, value, ¶m->oa_format);
|
||||
|
||||
if (ret) {
|
||||
drm_dbg(&oa->xe->drm, "Unsupported OA report format %#llx\n", value);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_exponent(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
#define OA_EXPONENT_MAX 31
|
||||
|
||||
if (value > OA_EXPONENT_MAX) {
|
||||
drm_dbg(&oa->xe->drm, "OA timer exponent too high (> %u)\n", OA_EXPONENT_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->period_exponent = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_disabled(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->disabled = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_exec_queue_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->exec_queue_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_engine_instance(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->engine_instance = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_no_preempt(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->no_preempt = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_set_property_fn)(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param);
|
||||
static const xe_oa_set_property_fn xe_oa_set_property_funcs[] = {
|
||||
[DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_oa_unit_id,
|
||||
[DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_sample_oa,
|
||||
[DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set,
|
||||
[DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_oa_format,
|
||||
[DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_oa_exponent,
|
||||
[DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_disabled,
|
||||
[DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_exec_queue_id,
|
||||
[DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_engine_instance,
|
||||
[DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_no_preempt,
|
||||
};
|
||||
|
||||
static int xe_oa_user_ext_set_property(struct xe_oa *oa, u64 extension,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_ext_set_property ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.property >= ARRAY_SIZE(xe_oa_set_property_funcs)) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.pad))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_oa_set_property_funcs));
|
||||
return xe_oa_set_property_funcs[idx](oa, ext.value, param);
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_user_extension_fn)(struct xe_oa *oa, u64 extension,
|
||||
struct xe_oa_open_param *param);
|
||||
static const xe_oa_user_extension_fn xe_oa_user_extension_funcs[] = {
|
||||
[DRM_XE_OA_EXTENSION_SET_PROPERTY] = xe_oa_user_ext_set_property,
|
||||
};
|
||||
|
||||
#define MAX_USER_EXTENSIONS 16
|
||||
static int xe_oa_user_extensions(struct xe_oa *oa, u64 extension, int ext_number,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_user_extension ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext_number >= MAX_USER_EXTENSIONS))
|
||||
return -E2BIG;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.pad) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.name >= ARRAY_SIZE(xe_oa_user_extension_funcs)))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.name, ARRAY_SIZE(xe_oa_user_extension_funcs));
|
||||
err = xe_oa_user_extension_funcs[idx](oa, extension, param);
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return err;
|
||||
|
||||
if (ext.next_extension)
|
||||
return xe_oa_user_extensions(oa, ext.next_extension, ++ext_number, param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_oa_stream_open_ioctl - Opens an OA stream
|
||||
* @dev: @drm_device
|
||||
@ -1812,7 +2054,8 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = xe_oa_user_extensions(oa, data, 0, ¶m);
|
||||
param.xef = xef;
|
||||
ret = xe_oa_user_extensions(oa, XE_OA_USER_EXTN_FROM_OPEN, data, 0, ¶m);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1880,11 +2123,24 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f
|
||||
drm_dbg(&oa->xe->drm, "Using periodic sampling freq %lld Hz\n", oa_freq_hz);
|
||||
}
|
||||
|
||||
ret = xe_oa_parse_syncs(oa, ¶m);
|
||||
if (ret)
|
||||
goto err_exec_q;
|
||||
|
||||
mutex_lock(¶m.hwe->gt->oa.gt_lock);
|
||||
ret = xe_oa_stream_open_ioctl_locked(oa, ¶m);
|
||||
mutex_unlock(¶m.hwe->gt->oa.gt_lock);
|
||||
if (ret < 0)
|
||||
goto err_sync_cleanup;
|
||||
|
||||
return ret;
|
||||
|
||||
err_sync_cleanup:
|
||||
while (param.num_syncs--)
|
||||
xe_sync_entry_cleanup(¶m.syncs[param.num_syncs]);
|
||||
kfree(param.syncs);
|
||||
err_exec_q:
|
||||
if (ret < 0 && param.exec_q)
|
||||
if (param.exec_q)
|
||||
xe_exec_queue_put(param.exec_q);
|
||||
return ret;
|
||||
}
|
||||
|
@ -238,5 +238,17 @@ struct xe_oa_stream {
|
||||
|
||||
/** @no_preempt: Whether preemption and timeslicing is disabled for stream exec_q */
|
||||
u32 no_preempt;
|
||||
|
||||
/** @xef: xe_file with which the stream was opened */
|
||||
struct xe_file *xef;
|
||||
|
||||
/** @last_fence: fence to use in stream destroy when needed */
|
||||
struct dma_fence *last_fence;
|
||||
|
||||
/** @num_syncs: size of @syncs array */
|
||||
u32 num_syncs;
|
||||
|
||||
/** @syncs: syncs to wait on and to signal */
|
||||
struct xe_sync_entry *syncs;
|
||||
};
|
||||
#endif
|
||||
|
@ -182,11 +182,12 @@ static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry ta
|
||||
static void xelp_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int i, err;
|
||||
unsigned int fw_ref;
|
||||
int i;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
goto err_fw;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
drm_printf(p, "PAT table:\n");
|
||||
|
||||
@ -198,9 +199,7 @@ static void xelp_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
XELP_MEM_TYPE_STR_MAP[mem_type], pat);
|
||||
}
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
err_fw:
|
||||
xe_assert(xe, !err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
static const struct xe_pat_ops xelp_pat_ops = {
|
||||
@ -211,11 +210,12 @@ static const struct xe_pat_ops xelp_pat_ops = {
|
||||
static void xehp_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int i, err;
|
||||
unsigned int fw_ref;
|
||||
int i;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
goto err_fw;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
drm_printf(p, "PAT table:\n");
|
||||
|
||||
@ -229,9 +229,7 @@ static void xehp_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
XELP_MEM_TYPE_STR_MAP[mem_type], pat);
|
||||
}
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
err_fw:
|
||||
xe_assert(xe, !err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
static const struct xe_pat_ops xehp_pat_ops = {
|
||||
@ -242,11 +240,12 @@ static const struct xe_pat_ops xehp_pat_ops = {
|
||||
static void xehpc_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int i, err;
|
||||
unsigned int fw_ref;
|
||||
int i;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
goto err_fw;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
drm_printf(p, "PAT table:\n");
|
||||
|
||||
@ -258,9 +257,7 @@ static void xehpc_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
REG_FIELD_GET(XEHPC_CLOS_LEVEL_MASK, pat), pat);
|
||||
}
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
err_fw:
|
||||
xe_assert(xe, !err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
static const struct xe_pat_ops xehpc_pat_ops = {
|
||||
@ -271,11 +268,12 @@ static const struct xe_pat_ops xehpc_pat_ops = {
|
||||
static void xelpg_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int i, err;
|
||||
unsigned int fw_ref;
|
||||
int i;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
goto err_fw;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
drm_printf(p, "PAT table:\n");
|
||||
|
||||
@ -292,9 +290,7 @@ static void xelpg_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
REG_FIELD_GET(XELPG_INDEX_COH_MODE_MASK, pat), pat);
|
||||
}
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
err_fw:
|
||||
xe_assert(xe, !err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -330,12 +326,13 @@ static void xe2lpm_program_pat(struct xe_gt *gt, const struct xe_pat_table_entry
|
||||
static void xe2_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int i, err;
|
||||
unsigned int fw_ref;
|
||||
u32 pat;
|
||||
int i;
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
goto err_fw;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return;
|
||||
|
||||
drm_printf(p, "PAT table:\n");
|
||||
|
||||
@ -374,9 +371,7 @@ static void xe2_dump(struct xe_gt *gt, struct drm_printer *p)
|
||||
REG_FIELD_GET(XE2_COH_MODE, pat),
|
||||
pat);
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
err_fw:
|
||||
xe_assert(xe, !err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
}
|
||||
|
||||
static const struct xe_pat_ops xe2_pat_ops = {
|
||||
|
@ -117,6 +117,7 @@ query_engine_cycles(struct xe_device *xe,
|
||||
__ktime_func_t cpu_clock;
|
||||
struct xe_hw_engine *hwe;
|
||||
struct xe_gt *gt;
|
||||
unsigned int fw_ref;
|
||||
|
||||
if (query->size == 0) {
|
||||
query->size = size;
|
||||
@ -149,13 +150,16 @@ query_engine_cycles(struct xe_device *xe,
|
||||
if (!hwe)
|
||||
return -EINVAL;
|
||||
|
||||
if (xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL))
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) {
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
hwe_read_timestamp(hwe, &resp.engine_cycles, &resp.cpu_timestamp,
|
||||
&resp.cpu_delta, cpu_clock);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
|
||||
if (GRAPHICS_VER(xe) >= 20)
|
||||
resp.width = 64;
|
||||
@ -666,7 +670,7 @@ static int query_oa_units(struct xe_device *xe,
|
||||
du->oa_unit_id = u->oa_unit_id;
|
||||
du->oa_unit_type = u->type;
|
||||
du->oa_timestamp_freq = xe_oa_timestamp_frequency(gt);
|
||||
du->capabilities = DRM_XE_OA_CAPS_BASE;
|
||||
du->capabilities = DRM_XE_OA_CAPS_BASE | DRM_XE_OA_CAPS_SYNCS;
|
||||
|
||||
j = 0;
|
||||
for_each_hw_engine(hwe, gt, hwe_id) {
|
||||
|
@ -188,27 +188,27 @@ void xe_reg_sr_apply_mmio(struct xe_reg_sr *sr, struct xe_gt *gt)
|
||||
{
|
||||
struct xe_reg_sr_entry *entry;
|
||||
unsigned long reg;
|
||||
int err;
|
||||
unsigned int fw_ref;
|
||||
|
||||
if (xa_empty(&sr->xa))
|
||||
return;
|
||||
|
||||
xe_gt_dbg(gt, "Applying %s save-restore MMIOs\n", sr->name);
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
goto err_force_wake;
|
||||
|
||||
xa_for_each(&sr->xa, reg, entry)
|
||||
apply_one_mmio(gt, entry);
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
XE_WARN_ON(err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
|
||||
return;
|
||||
|
||||
err_force_wake:
|
||||
xe_gt_err(gt, "Failed to apply, err=%d\n", err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
xe_gt_err(gt, "Failed to apply, err=-ETIMEDOUT\n");
|
||||
}
|
||||
|
||||
void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe)
|
||||
@ -221,15 +221,15 @@ void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe)
|
||||
u32 mmio_base = hwe->mmio_base;
|
||||
unsigned long reg;
|
||||
unsigned int slot = 0;
|
||||
int err;
|
||||
unsigned int fw_ref;
|
||||
|
||||
if (xa_empty(&sr->xa))
|
||||
return;
|
||||
|
||||
drm_dbg(&xe->drm, "Whitelisting %s registers\n", sr->name);
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (err)
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL))
|
||||
goto err_force_wake;
|
||||
|
||||
p = drm_dbg_printer(&xe->drm, DRM_UT_DRIVER, NULL);
|
||||
@ -254,13 +254,13 @@ void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe)
|
||||
xe_mmio_write32(>->mmio, RING_FORCE_TO_NONPRIV(mmio_base, slot), addr);
|
||||
}
|
||||
|
||||
err = xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL);
|
||||
XE_WARN_ON(err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
|
||||
return;
|
||||
|
||||
err_force_wake:
|
||||
drm_err(&xe->drm, "Failed to apply, err=%d\n", err);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
drm_err(&xe->drm, "Failed to apply, err=-ETIMEDOUT\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -280,7 +280,7 @@ void xe_sched_job_arm(struct xe_sched_job *job)
|
||||
fence = &chain->base;
|
||||
}
|
||||
|
||||
job->fence = fence;
|
||||
job->fence = dma_fence_get(fence); /* Pairs with put in scheduler */
|
||||
drm_sched_job_arm(&job->drm);
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,6 @@ struct xe_sched_job {
|
||||
* @fence: dma fence to indicate completion. 1 way relationship - job
|
||||
* can safely reference fence, fence cannot safely reference job.
|
||||
*/
|
||||
#define JOB_FLAG_SUBMIT DMA_FENCE_FLAG_USER_BITS
|
||||
struct dma_fence *fence;
|
||||
/** @user_fence: write back value when BB is complete */
|
||||
struct {
|
||||
@ -63,7 +62,7 @@ struct xe_sched_job {
|
||||
|
||||
struct xe_sched_job_snapshot {
|
||||
u16 batch_addr_len;
|
||||
u64 batch_addr[];
|
||||
u64 batch_addr[] __counted_by(batch_addr_len);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -83,6 +83,8 @@ static void user_fence_worker(struct work_struct *w)
|
||||
XE_WARN_ON("Copy to user failed");
|
||||
kthread_unuse_mm(ufence->mm);
|
||||
mmput(ufence->mm);
|
||||
} else {
|
||||
drm_dbg(&ufence->xe->drm, "mmget_not_zero() failed, ufence wasn't signaled\n");
|
||||
}
|
||||
|
||||
wake_up_all(&ufence->xe->ufence_wq);
|
||||
|
@ -220,8 +220,8 @@ static int tile_vram_size(struct xe_tile *tile, u64 *vram_size,
|
||||
{
|
||||
struct xe_device *xe = tile_to_xe(tile);
|
||||
struct xe_gt *gt = tile->primary_gt;
|
||||
unsigned int fw_ref;
|
||||
u64 offset;
|
||||
int err;
|
||||
u32 reg;
|
||||
|
||||
if (IS_SRIOV_VF(xe)) {
|
||||
@ -240,9 +240,9 @@ static int tile_vram_size(struct xe_tile *tile, u64 *vram_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (err)
|
||||
return err;
|
||||
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
|
||||
if (!fw_ref)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* actual size */
|
||||
if (unlikely(xe->info.platform == XE_DG1)) {
|
||||
@ -264,7 +264,9 @@ static int tile_vram_size(struct xe_tile *tile, u64 *vram_size,
|
||||
/* remove the tile offset so we have just the available size */
|
||||
*vram_size = offset - *tile_offset;
|
||||
|
||||
return xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
xe_force_wake_put(gt_to_fw(gt), fw_ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vram_fini(void *arg)
|
||||
|
@ -39,3 +39,5 @@
|
||||
14019789679 GRAPHICS_VERSION(1255)
|
||||
GRAPHICS_VERSION_RANGE(1270, 2004)
|
||||
no_media_l3 MEDIA_VERSION(3000)
|
||||
14022866841 GRAPHICS_VERSION(3000), GRAPHICS_STEP(A0, B0)
|
||||
MEDIA_VERSION(3000), MEDIA_STEP(A0, B0)
|
||||
|
@ -1485,6 +1485,7 @@ struct drm_xe_oa_unit {
|
||||
/** @capabilities: OA capabilities bit-mask */
|
||||
__u64 capabilities;
|
||||
#define DRM_XE_OA_CAPS_BASE (1 << 0)
|
||||
#define DRM_XE_OA_CAPS_SYNCS (1 << 1)
|
||||
|
||||
/** @oa_timestamp_freq: OA timestamp freq */
|
||||
__u64 oa_timestamp_freq;
|
||||
@ -1634,6 +1635,22 @@ enum drm_xe_oa_property_id {
|
||||
* to be disabled for the stream exec queue.
|
||||
*/
|
||||
DRM_XE_OA_PROPERTY_NO_PREEMPT,
|
||||
|
||||
/**
|
||||
* @DRM_XE_OA_PROPERTY_NUM_SYNCS: Number of syncs in the sync array
|
||||
* specified in @DRM_XE_OA_PROPERTY_SYNCS
|
||||
*/
|
||||
DRM_XE_OA_PROPERTY_NUM_SYNCS,
|
||||
|
||||
/**
|
||||
* @DRM_XE_OA_PROPERTY_SYNCS: Pointer to struct @drm_xe_sync array
|
||||
* with array size specified via @DRM_XE_OA_PROPERTY_NUM_SYNCS. OA
|
||||
* configuration will wait till input fences signal. Output fences
|
||||
* will signal after the new OA configuration takes effect. For
|
||||
* @DRM_XE_SYNC_TYPE_USER_FENCE, @addr is a user pointer, similar
|
||||
* to the VM bind case.
|
||||
*/
|
||||
DRM_XE_OA_PROPERTY_SYNCS,
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user