[Intel-xe] [RFC 21/25] drm/xe/: Include attention in usercapture.
Mika Kuoppala
mika.kuoppala at linux.intel.com
Mon Nov 6 11:18:41 UTC 2023
From: Dominik Grzegorzek <dominik.grzegorzek at intel.com>
Signed-off-by: Dominik Grzegorzek <dominik.grzegorzek at intel.com>
---
drivers/gpu/drm/xe/xe_eudebug.c | 24 +++-
drivers/gpu/drm/xe/xe_usercoredump.c | 140 +++++++++++++++++++++
drivers/gpu/drm/xe/xe_usercoredump_types.h | 18 +++
3 files changed, 180 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_eudebug.c b/drivers/gpu/drm/xe/xe_eudebug.c
index a5cae53fe496..886da91ea0a4 100644
--- a/drivers/gpu/drm/xe/xe_eudebug.c
+++ b/drivers/gpu/drm/xe/xe_eudebug.c
@@ -16,6 +16,8 @@
#include "regs/xe_engine_regs.h"
#include "regs/xe_gt_regs.h"
+#include "xe_devcoredump.h"
+#include "xe_usercoredump.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_gt_debug.h"
@@ -1031,7 +1033,9 @@ static struct xe_exec_queue *runalone_active_queue_get(struct xe_gt *gt, int *lr
xe_exec_queue_get(q);
found = q;
- *lrc_idx = idx;
+
+ if (lrc_idx)
+ *lrc_idx = idx;
break;
}
@@ -1187,10 +1191,26 @@ static void attention_scan_fn(struct work_struct *work)
ret = xe_eudebug_handle_gt_attention(gt);
if (ret) {
- // TODO: error capture
+ struct xe_exec_queue *eq;
+
drm_info(>_to_xe(gt)->drm,
"gt:%d unable to handle eu attention ret=%d\n",
gt_id, ret);
+
+ eq = runalone_active_queue_get(gt, NULL);
+ if (!IS_ERR(eq)) {
+ struct xe_user_state_snapshot *s;
+
+ s = xe_user_state_snapshot_capture(eq);
+ if (s)
+ xe_usercoredumps_add(xe, s);
+
+ xe_devcoredump(eq);
+ } else {
+ drm_info(>_to_xe(gt)->drm,
+ "cannot determine active request, set runalone\n");
+ }
+
xe_gt_reset_async(gt);
}
}
diff --git a/drivers/gpu/drm/xe/xe_usercoredump.c b/drivers/gpu/drm/xe/xe_usercoredump.c
index 27b201641e4d..1b90fecb1472 100644
--- a/drivers/gpu/drm/xe/xe_usercoredump.c
+++ b/drivers/gpu/drm/xe/xe_usercoredump.c
@@ -5,10 +5,13 @@
#include "xe_usercoredump.h"
+#include <linux/delay.h>
+#include "regs/xe_gt_regs.h"
#include "xe_debug_metadata.h"
#include "xe_device_types.h"
#include "xe_exec_queue_types.h"
+#include "xe_gt_mcr.h"
#include "xe_vm.h"
#include "xe_bo.h"
#include "xe_res_cursor.h"
@@ -239,6 +242,106 @@ static void capture_metadata(struct xe_user_state_snapshot *s,
xe_vm_put(vm);
}
+static inline unsigned int
+xe_eu_attentions_count(const struct xe_eu_attentions_snapshot *a)
+{
+ return bitmap_weight((void *)a->att, a->size * BITS_PER_BYTE);
+}
+
+static void xe_eu_attentions_read(struct xe_exec_queue *eq,
+ struct xe_eu_attentions_snapshot *a,
+ const unsigned int settle_time_ms)
+{
+ struct xe_gt *gt = eq->gt;
+ unsigned int prev = 0;
+ ktime_t end, now;
+
+ now = ktime_get_raw();
+ end = ktime_add_ms(now, settle_time_ms);
+
+ a->ts = 0;
+ a->size = min_t(int,
+ xe_gt_eu_attention_bitmap_size(gt),
+ sizeof(a->att));
+
+ do {
+ unsigned int attn;
+
+ xe_gt_eu_attention_bitmap(gt, a->att, a->size);
+ attn = xe_eu_attentions_count(a);
+
+ now = ktime_get_raw();
+
+ if (a->ts == 0)
+ a->ts = now;
+ else if (attn && attn != prev)
+ a->ts = now;
+
+ prev = attn;
+
+ if (settle_time_ms)
+ udelay(5);
+
+ /*
+ * XXX We are gathering data for production SIP to find
+ * the upper limit of settle time. For now, we wait full
+ * timeout value regardless.
+ */
+ } while (ktime_before(now, end));
+}
+
+static void capture_attentions(struct xe_user_state_snapshot *s,
+ struct xe_exec_queue *eq)
+{
+ struct xe_gt *gt = eq->gt;
+ u32 td_ctl;
+ int ret;
+
+ ret = xe_force_wake_get(gt_to_fw(gt), eq->hwe->domain);
+
+ if (ret)
+ return;
+
+ td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+ s->attentions.td_ctl = td_ctl;
+
+ xe_eu_attentions_read(eq, &s->attentions.before, 0);
+
+ /* If there is no debug functionality, dont invoke sip */
+ if (!td_ctl)
+ goto put_fw;
+
+ /* Halt on next thread dispatch */
+ while (!(td_ctl & TD_CTL_FORCE_EXTERNAL_HALT)) {
+ xe_gt_mcr_multicast_write(gt, TD_CTL,
+ td_ctl | TD_CTL_FORCE_EXTERNAL_HALT);
+ /*
+ * The sleep is needed because some interrupts are ignored
+ * by the HW, hence we allow the HW some time to acknowledge
+ * that.
+ */
+ udelay(200);
+
+ td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+ }
+
+ /* Halt regardless of thread dependencies */
+ while (!(td_ctl & TD_CTL_FORCE_EXCEPTION)) {
+ xe_gt_mcr_multicast_write(gt, TD_CTL,
+ td_ctl | TD_CTL_FORCE_EXCEPTION);
+ udelay(200);
+
+ td_ctl = xe_gt_mcr_unicast_read_any(gt, TD_CTL);
+ }
+
+ xe_eu_attentions_read(eq, &s->attentions.after,
+ XE_GT_ATTENTION_TIMEOUT_MS);
+
+put_fw:
+ xe_force_wake_put(gt_to_fw(gt), eq->hwe->domain);
+
+}
+
static void hexdump(struct drm_printer *m, const void *buf, size_t len)
{
const size_t rowsize = 8 * sizeof(u32);
@@ -314,6 +417,40 @@ static const char *vm_metadata_type_to_str(const u64 type)
return "Unknown";
}
+static void __print_attn(struct drm_printer *p,
+ const char *name,
+ const struct xe_eu_attentions_snapshot *a,
+ ktime_t epoc)
+{
+ int max = a->size * BITS_PER_BYTE;
+ const u32 *bm = (const u32 *)a->att;
+ unsigned int count;
+
+ count = xe_eu_attentions_count(a);
+
+ drm_printf(p, "TD_ATT %s (%d):", name, count);
+
+ max /= BITS_PER_TYPE(*bm);
+ while (max--)
+ drm_printf(p, " %08x", *bm++);
+
+ if (count && epoc)
+ drm_printf(p, " %lldus after FEH\n",
+ ktime_us_delta(a->ts, epoc));
+ else
+ drm_printf(p, "\n");
+}
+
+static void xe_attentions_snapshot_print(struct xe_user_state_snapshot *s,
+ struct drm_printer *p)
+{
+ const ktime_t halt_ts = s->attentions.before.ts;
+
+ drm_printf(p, "TD_CTL: 0x%08x\n", s->attentions.td_ctl);
+ __print_attn(p, "before", &s->attentions.before, 0);
+ __print_attn(p, "after", &s->attentions.after, halt_ts);
+}
+
void xe_user_state_snapshot_print(struct xe_user_state_snapshot *s,
struct drm_printer *p)
{
@@ -347,6 +484,8 @@ void xe_user_state_snapshot_print(struct xe_user_state_snapshot *s,
upper_32_bits(s->vm_metadata[i].value),
lower_32_bits(s->vm_metadata[i].value),
s->vm_metadata[i].len);
+
+ xe_attentions_snapshot_print(s, p);
}
struct xe_user_state_snapshot *
@@ -377,6 +516,7 @@ xe_user_state_snapshot_capture(struct xe_exec_queue *q)
strcpy(s->comm, "");
}
+ capture_attentions(s, q);
capture_vmas(s, q);
capture_metadata(s, xef, q->vm);
diff --git a/drivers/gpu/drm/xe/xe_usercoredump_types.h b/drivers/gpu/drm/xe/xe_usercoredump_types.h
index 10950e127670..b3aa29f23096 100644
--- a/drivers/gpu/drm/xe/xe_usercoredump_types.h
+++ b/drivers/gpu/drm/xe/xe_usercoredump_types.h
@@ -12,6 +12,7 @@
#include <linux/xarray.h>
#include <drm/xe_drm.h>
+#include "xe_gt_debug.h"
struct xe_device;
struct xe_pidroot;
@@ -37,6 +38,16 @@ struct xe_debug_metadata_snapshot {
struct xe_debug_metadata *mdata;
};
+struct xe_eu_attentions_snapshot {
+#define MAX_EUS_PER_ROW 4u
+#define MAX_THREADS 8u
+
+ u8 att[XE_MAX_DSS_FUSE_BITS * TD_EU_ATTENTION_MAX_ROWS *
+ MAX_THREADS * MAX_EUS_PER_ROW / 8];
+ unsigned int size;
+ ktime_t ts;
+};
+
/**
* struct xe_user_state_snapshot - Crash snapshot
*
@@ -59,6 +70,13 @@ struct xe_user_state_snapshot {
u64 len;
} vm_metadata[DRM_XE_VM_DEBUG_METADATA_NUM];
+ struct {
+ u32 td_ctl; /* can be in power ctx on newer gens */
+
+ struct xe_eu_attentions_snapshot before;
+ struct xe_eu_attentions_snapshot after;
+ } attentions;
+
struct pid *pid;
u64 client_id; /* drm client id */
char comm[TASK_COMM_LEN];
--
2.34.1
More information about the Intel-xe
mailing list