summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2024-12-06 07:53:59 +1000
committerDave Airlie <airlied@redhat.com>2024-12-06 07:54:17 +1000
commit915bac607f02bede85c08da7c79a733ffc03b7ee (patch)
treed49f779da93bef0a04c5624d22cba39c054c90ae
parentdefc06f7ef163b64cff11990e8847bc225bcdd46 (diff)
parent5dce85fecb87751ec94526e1ac516dd7871e2e0c (diff)
Merge tag 'drm-xe-fixes-2024-12-04' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-fixes
Driver Changes: - Missing init value and 64-bit write-order check (Zhanjung) - Fix a memory allocation issue causing lockdep violation (John) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Hellstrom <thomas.hellstrom@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/Z1BidZBFQOLjz__J@fedora
-rw-r--r--drivers/gpu/drm/xe/xe_devcoredump.c73
-rw-r--r--drivers/gpu/drm/xe/xe_guc_capture.c77
2 files changed, 101 insertions, 49 deletions
diff --git a/drivers/gpu/drm/xe/xe_devcoredump.c b/drivers/gpu/drm/xe/xe_devcoredump.c
index 0b0cd6aa1d9f..f8947e7e917e 100644
--- a/drivers/gpu/drm/xe/xe_devcoredump.c
+++ b/drivers/gpu/drm/xe/xe_devcoredump.c
@@ -155,36 +155,6 @@ static void xe_devcoredump_snapshot_free(struct xe_devcoredump_snapshot *ss)
ss->vm = NULL;
}
-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);
- struct xe_device *xe = coredump_to_xe(coredump);
- unsigned int fw_ref;
-
- xe_pm_runtime_get(xe);
-
- /* keep going if fw fails as we still want to save the memory and SW data */
- 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), fw_ref);
-
- xe_pm_runtime_put(xe);
-
- /* Calculate devcoredump size */
- ss->read.size = __xe_devcoredump_read(NULL, INT_MAX, coredump);
-
- ss->read.buffer = kvmalloc(ss->read.size, GFP_USER);
- if (!ss->read.buffer)
- return;
-
- __xe_devcoredump_read(ss->read.buffer, ss->read.size, coredump);
- xe_devcoredump_snapshot_free(ss);
-}
-
static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
size_t count, void *data, size_t datalen)
{
@@ -234,6 +204,45 @@ static void xe_devcoredump_free(void *data)
"Xe device coredump has been deleted.\n");
}
+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);
+ struct xe_device *xe = coredump_to_xe(coredump);
+ unsigned int fw_ref;
+
+ /*
+ * NB: Despite passing a GFP_ flags parameter here, more allocations are done
+ * internally using GFP_KERNEL expliictly. Hence this call must be in the worker
+ * thread and not in the initial capture call.
+ */
+ dev_coredumpm_timeout(gt_to_xe(ss->gt)->drm.dev, THIS_MODULE, coredump, 0, GFP_KERNEL,
+ xe_devcoredump_read, xe_devcoredump_free,
+ XE_COREDUMP_TIMEOUT_JIFFIES);
+
+ xe_pm_runtime_get(xe);
+
+ /* keep going if fw fails as we still want to save the memory and SW data */
+ 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), fw_ref);
+
+ xe_pm_runtime_put(xe);
+
+ /* Calculate devcoredump size */
+ ss->read.size = __xe_devcoredump_read(NULL, INT_MAX, coredump);
+
+ ss->read.buffer = kvmalloc(ss->read.size, GFP_USER);
+ if (!ss->read.buffer)
+ return;
+
+ __xe_devcoredump_read(ss->read.buffer, ss->read.size, coredump);
+ xe_devcoredump_snapshot_free(ss);
+}
+
static void devcoredump_snapshot(struct xe_devcoredump *coredump,
struct xe_sched_job *job)
{
@@ -310,10 +319,6 @@ void xe_devcoredump(struct xe_sched_job *job)
drm_info(&xe->drm, "Xe device coredump has been created\n");
drm_info(&xe->drm, "Check your /sys/class/drm/card%d/device/devcoredump/data\n",
xe->drm.primary->index);
-
- dev_coredumpm_timeout(xe->drm.dev, THIS_MODULE, coredump, 0, GFP_KERNEL,
- xe_devcoredump_read, xe_devcoredump_free,
- XE_COREDUMP_TIMEOUT_JIFFIES);
}
static void xe_driver_devcoredump_fini(void *arg)
diff --git a/drivers/gpu/drm/xe/xe_guc_capture.c b/drivers/gpu/drm/xe/xe_guc_capture.c
index cc72446a5de1..d63912d28246 100644
--- a/drivers/gpu/drm/xe/xe_guc_capture.c
+++ b/drivers/gpu/drm/xe/xe_guc_capture.c
@@ -102,6 +102,7 @@ struct __guc_capture_parsed_output {
* A 64 bit register define requires 2 consecutive entries,
* with low dword first and hi dword the second.
* 2. Register name: null for incompleted define
+ * 3. Incorrect order will trigger XE_WARN.
*/
#define COMMON_XELP_BASE_GLOBAL \
{ FORCEWAKE_GT, REG_32BIT, 0, 0, "FORCEWAKE_GT"}
@@ -1675,10 +1676,10 @@ snapshot_print_by_list_order(struct xe_hw_engine_snapshot *snapshot, struct drm_
struct xe_devcoredump *devcoredump = &xe->devcoredump;
struct xe_devcoredump_snapshot *devcore_snapshot = &devcoredump->snapshot;
struct gcap_reg_list_info *reginfo = NULL;
- u32 last_value, i;
- bool is_ext;
+ u32 i, last_value = 0;
+ bool is_ext, low32_ready = false;
- if (!list || list->num_regs == 0)
+ if (!list || !list->list || list->num_regs == 0)
return;
XE_WARN_ON(!devcore_snapshot->matched_node);
@@ -1701,29 +1702,75 @@ snapshot_print_by_list_order(struct xe_hw_engine_snapshot *snapshot, struct drm_
continue;
value = reg->value;
- if (reg_desc->data_type == REG_64BIT_LOW_DW) {
+ switch (reg_desc->data_type) {
+ case REG_64BIT_LOW_DW:
last_value = value;
+
+ /*
+ * A 64 bit register define requires 2 consecutive
+ * entries in register list, with low dword first
+ * and hi dword the second, like:
+ * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
+ * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, "XXX_REG"},
+ *
+ * Incorrect order will trigger XE_WARN.
+ *
+ * Possible double low here, for example:
+ * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
+ * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
+ */
+ XE_WARN_ON(low32_ready);
+ low32_ready = true;
/* Low 32 bit dword saved, continue for high 32 bit */
- continue;
- } else if (reg_desc->data_type == REG_64BIT_HI_DW) {
+ break;
+
+ case REG_64BIT_HI_DW: {
u64 value_qw = ((u64)value << 32) | last_value;
+ /*
+ * Incorrect 64bit register order. Possible missing low.
+ * for example:
+ * { XXX_REG(0), REG_32BIT, 0, 0, NULL},
+ * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, NULL},
+ */
+ XE_WARN_ON(!low32_ready);
+ low32_ready = false;
+
drm_printf(p, "\t%s: 0x%016llx\n", reg_desc->regname, value_qw);
- continue;
+ break;
}
- if (is_ext) {
- int dss, group, instance;
+ case REG_32BIT:
+ /*
+ * Incorrect 64bit register order. Possible missing high.
+ * for example:
+ * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
+ * { XXX_REG(0), REG_32BIT, 0, 0, "XXX_REG"},
+ */
+ XE_WARN_ON(low32_ready);
+
+ if (is_ext) {
+ int dss, group, instance;
- group = FIELD_GET(GUC_REGSET_STEERING_GROUP, reg_desc->flags);
- instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, reg_desc->flags);
- dss = xe_gt_mcr_steering_info_to_dss_id(gt, group, instance);
+ group = FIELD_GET(GUC_REGSET_STEERING_GROUP, reg_desc->flags);
+ instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, reg_desc->flags);
+ dss = xe_gt_mcr_steering_info_to_dss_id(gt, group, instance);
- drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname, dss, value);
- } else {
- drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value);
+ drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname, dss, value);
+ } else {
+ drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value);
+ }
+ break;
}
}
+
+ /*
+ * Incorrect 64bit register order. Possible missing high.
+ * for example:
+ * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
+ * } // <- Register list end
+ */
+ XE_WARN_ON(low32_ready);
}
/**