Commit 24492514 authored by Alan Previn's avatar Alan Previn Committed by Lucas De Marchi

drm/i915/guc: Update GuC ADS size for error capture lists

Update GuC ADS size allocation to include space for
the lists of error state capture register descriptors.

Then, populate GuC ADS with the lists of registers we want
GuC to report back to host on engine reset events. This list
should include global, engine-class and engine-instance
registers for every engine-class type on the current hardware.

Ensure we allocate a persistent store for the register lists
that are populated into ADS so that we don't need to allocate
memory during GT resets when GuC is reloaded and ADS population
happens again.

NOTE: Start with a sample static table of register lists to
layout the framework before adding real registers in subsequent
patch. This static register tables are a different format from
the ADS populated list.
Signed-off-by: default avatarAlan Previn <alan.previn.teres.alexis@intel.com>
Reviewed-by: default avatarMatthew Brost <matthew.brost@intel.com>
Signed-off-by: default avatarLucas De Marchi <lucas.demarchi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220321164527.2500062-2-alan.previn.teres.alexis@intel.com
parent 61c5ed94
...@@ -186,6 +186,7 @@ i915-y += gt/uc/intel_uc.o \ ...@@ -186,6 +186,7 @@ i915-y += gt/uc/intel_uc.o \
gt/uc/intel_uc_fw.o \ gt/uc/intel_uc_fw.o \
gt/uc/intel_guc.o \ gt/uc/intel_guc.o \
gt/uc/intel_guc_ads.o \ gt/uc/intel_guc_ads.o \
gt/uc/intel_guc_capture.o \
gt/uc/intel_guc_ct.o \ gt/uc/intel_guc_ct.o \
gt/uc/intel_guc_debugfs.o \ gt/uc/intel_guc_debugfs.o \
gt/uc/intel_guc_fw.o \ gt/uc/intel_guc_fw.o \
......
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2021-2022 Intel Corporation
*/
#ifndef _INTEL_GUC_CAPTURE_FWIF_H
#define _INTEL_GUC_CAPTURE_FWIF_H
#include <linux/types.h>
#include "intel_guc_fwif.h"
struct intel_guc;
struct file;
/**
* struct guc_debug_capture_list_header / struct guc_debug_capture_list
*
* As part of ADS registration, these header structures (followed by
* an array of 'struct guc_mmio_reg' entries) are used to register with
* GuC microkernel the list of registers we want it to dump out prior
* to a engine reset.
*/
struct guc_debug_capture_list_header {
u32 info;
#define GUC_CAPTURELISTHDR_NUMDESCR GENMASK(15, 0)
} __packed;
struct guc_debug_capture_list {
struct guc_debug_capture_list_header header;
struct guc_mmio_reg regs[0];
} __packed;
/**
* struct __guc_mmio_reg_descr / struct __guc_mmio_reg_descr_group
*
* intel_guc_capture module uses these structures to maintain static
* tables (per unique platform) that consists of lists of registers
* (offsets, names, flags,...) that are used at the ADS regisration
* time as well as during runtime processing and reporting of error-
* capture states generated by GuC just prior to engine reset events.
*/
struct __guc_mmio_reg_descr {
i915_reg_t reg;
u32 flags;
u32 mask;
const char *regname;
};
struct __guc_mmio_reg_descr_group {
const struct __guc_mmio_reg_descr *list;
u32 num_regs;
u32 owner; /* see enum guc_capture_owner */
u32 type; /* see enum guc_capture_type */
u32 engine; /* as per MAX_ENGINE_CLASS */
};
/**
* struct __guc_capture_ads_cache
*
* A structure to cache register lists that were populated and registered
* with GuC at startup during ADS registration. This allows much quicker
* GuC resets without re-parsing all the tables for the given gt.
*/
struct __guc_capture_ads_cache {
bool is_valid;
void *ptr;
size_t size;
int status;
};
/**
* struct intel_guc_state_capture
*
* Internal context of the intel_guc_capture module.
*/
struct intel_guc_state_capture {
/**
* @reglists: static table of register lists used for error-capture state.
*/
const struct __guc_mmio_reg_descr_group *reglists;
/**
* @ads_cache: cached register lists that is ADS format ready
*/
struct __guc_capture_ads_cache ads_cache[GUC_CAPTURE_LIST_INDEX_MAX]
[GUC_CAPTURE_LIST_TYPE_MAX]
[GUC_MAX_ENGINE_CLASSES];
void *ads_null_cache;
};
#endif /* _INTEL_GUC_CAPTURE_FWIF_H */
...@@ -9,8 +9,9 @@ ...@@ -9,8 +9,9 @@
#include "gt/intel_gt_pm_irq.h" #include "gt/intel_gt_pm_irq.h"
#include "gt/intel_gt_regs.h" #include "gt/intel_gt_regs.h"
#include "intel_guc.h" #include "intel_guc.h"
#include "intel_guc_slpc.h"
#include "intel_guc_ads.h" #include "intel_guc_ads.h"
#include "intel_guc_capture.h"
#include "intel_guc_slpc.h"
#include "intel_guc_submission.h" #include "intel_guc_submission.h"
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_irq.h" #include "i915_irq.h"
...@@ -362,9 +363,14 @@ int intel_guc_init(struct intel_guc *guc) ...@@ -362,9 +363,14 @@ int intel_guc_init(struct intel_guc *guc)
if (ret) if (ret)
goto err_fw; goto err_fw;
ret = intel_guc_ads_create(guc); ret = intel_guc_capture_init(guc);
if (ret) if (ret)
goto err_log; goto err_log;
ret = intel_guc_ads_create(guc);
if (ret)
goto err_capture;
GEM_BUG_ON(!guc->ads_vma); GEM_BUG_ON(!guc->ads_vma);
ret = intel_guc_ct_init(&guc->ct); ret = intel_guc_ct_init(&guc->ct);
...@@ -403,6 +409,8 @@ int intel_guc_init(struct intel_guc *guc) ...@@ -403,6 +409,8 @@ int intel_guc_init(struct intel_guc *guc)
intel_guc_ct_fini(&guc->ct); intel_guc_ct_fini(&guc->ct);
err_ads: err_ads:
intel_guc_ads_destroy(guc); intel_guc_ads_destroy(guc);
err_capture:
intel_guc_capture_destroy(guc);
err_log: err_log:
intel_guc_log_destroy(&guc->log); intel_guc_log_destroy(&guc->log);
err_fw: err_fw:
...@@ -430,6 +438,7 @@ void intel_guc_fini(struct intel_guc *guc) ...@@ -430,6 +438,7 @@ void intel_guc_fini(struct intel_guc *guc)
intel_guc_ct_fini(&guc->ct); intel_guc_ct_fini(&guc->ct);
intel_guc_ads_destroy(guc); intel_guc_ads_destroy(guc);
intel_guc_capture_destroy(guc);
intel_guc_log_destroy(&guc->log); intel_guc_log_destroy(&guc->log);
intel_uc_fw_fini(&guc->fw); intel_uc_fw_fini(&guc->fw);
} }
......
...@@ -10,18 +10,19 @@ ...@@ -10,18 +10,19 @@
#include <linux/iosys-map.h> #include <linux/iosys-map.h>
#include <linux/xarray.h> #include <linux/xarray.h>
#include "intel_uncore.h" #include "intel_guc_ct.h"
#include "intel_guc_fw.h" #include "intel_guc_fw.h"
#include "intel_guc_fwif.h" #include "intel_guc_fwif.h"
#include "intel_guc_ct.h"
#include "intel_guc_log.h" #include "intel_guc_log.h"
#include "intel_guc_reg.h" #include "intel_guc_reg.h"
#include "intel_guc_slpc_types.h" #include "intel_guc_slpc_types.h"
#include "intel_uc_fw.h" #include "intel_uc_fw.h"
#include "intel_uncore.h"
#include "i915_utils.h" #include "i915_utils.h"
#include "i915_vma.h" #include "i915_vma.h"
struct __guc_ads_blob; struct __guc_ads_blob;
struct intel_guc_state_capture;
/** /**
* struct intel_guc - Top level structure of GuC. * struct intel_guc - Top level structure of GuC.
...@@ -38,6 +39,8 @@ struct intel_guc { ...@@ -38,6 +39,8 @@ struct intel_guc {
struct intel_guc_ct ct; struct intel_guc_ct ct;
/** @slpc: sub-structure containing SLPC related data and objects */ /** @slpc: sub-structure containing SLPC related data and objects */
struct intel_guc_slpc slpc; struct intel_guc_slpc slpc;
/** @capture: the error-state-capture module's data and objects */
struct intel_guc_state_capture *capture;
/** @sched_engine: Global engine used to submit requests to GuC */ /** @sched_engine: Global engine used to submit requests to GuC */
struct i915_sched_engine *sched_engine; struct i915_sched_engine *sched_engine;
...@@ -162,6 +165,8 @@ struct intel_guc { ...@@ -162,6 +165,8 @@ struct intel_guc {
struct guc_mmio_reg *ads_regset; struct guc_mmio_reg *ads_regset;
/** @ads_golden_ctxt_size: size of the golden contexts in the ADS */ /** @ads_golden_ctxt_size: size of the golden contexts in the ADS */
u32 ads_golden_ctxt_size; u32 ads_golden_ctxt_size;
/** @ads_capture_size: size of register lists in the ADS used for error capture */
u32 ads_capture_size;
/** @ads_engine_usage_size: size of engine usage in the ADS */ /** @ads_engine_usage_size: size of engine usage in the ADS */
u32 ads_engine_usage_size; u32 ads_engine_usage_size;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "gt/intel_lrc.h" #include "gt/intel_lrc.h"
#include "gt/shmem_utils.h" #include "gt/shmem_utils.h"
#include "intel_guc_ads.h" #include "intel_guc_ads.h"
#include "intel_guc_capture.h"
#include "intel_guc_fwif.h" #include "intel_guc_fwif.h"
#include "intel_uc.h" #include "intel_uc.h"
#include "i915_drv.h" #include "i915_drv.h"
...@@ -86,8 +87,7 @@ static u32 guc_ads_golden_ctxt_size(struct intel_guc *guc) ...@@ -86,8 +87,7 @@ static u32 guc_ads_golden_ctxt_size(struct intel_guc *guc)
static u32 guc_ads_capture_size(struct intel_guc *guc) static u32 guc_ads_capture_size(struct intel_guc *guc)
{ {
/* FIXME: Allocate a proper capture list */ return PAGE_ALIGN(guc->ads_capture_size);
return PAGE_ALIGN(PAGE_SIZE);
} }
static u32 guc_ads_private_data_size(struct intel_guc *guc) static u32 guc_ads_private_data_size(struct intel_guc *guc)
...@@ -611,24 +611,119 @@ static void guc_init_golden_context(struct intel_guc *guc) ...@@ -611,24 +611,119 @@ static void guc_init_golden_context(struct intel_guc *guc)
GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size); GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
} }
static void guc_capture_list_init(struct intel_guc *guc) static int
guc_capture_prep_lists(struct intel_guc *guc)
{ {
struct intel_gt *gt = guc_to_gt(guc);
struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
u32 ads_ggtt, capture_offset, null_ggtt, total_size = 0;
struct guc_gt_system_info local_info;
struct iosys_map info_map;
bool ads_is_mapped;
size_t size = 0;
void *ptr;
int i, j; int i, j;
u32 addr_ggtt, offset;
offset = guc_ads_capture_offset(guc); ads_is_mapped = !iosys_map_is_null(&guc->ads_map);
addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset; if (ads_is_mapped) {
capture_offset = guc_ads_capture_offset(guc);
ads_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma);
info_map = IOSYS_MAP_INIT_OFFSET(&guc->ads_map,
offsetof(struct __guc_ads_blob, system_info));
} else {
memset(&local_info, 0, sizeof(local_info));
iosys_map_set_vaddr(&info_map, &local_info);
fill_engine_enable_masks(gt, &info_map);
}
/* FIXME: Populate a proper capture list */ /* first, set aside the first page for a capture_list with zero descriptors */
total_size = PAGE_SIZE;
if (ads_is_mapped) {
if (!intel_guc_capture_getnullheader(guc, &ptr, &size))
iosys_map_memcpy_to(&guc->ads_map, capture_offset, ptr, size);
null_ggtt = ads_ggtt + capture_offset;
capture_offset += PAGE_SIZE;
}
for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) { for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) { for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
ads_blob_write(guc, ads.capture_instance[i][j], addr_ggtt);
ads_blob_write(guc, ads.capture_class[i][j], addr_ggtt);
}
ads_blob_write(guc, ads.capture_global[i], addr_ggtt); /* null list if we dont have said engine or list */
if (!info_map_read(&info_map, engine_enabled_masks[j])) {
if (ads_is_mapped) {
ads_blob_write(guc, ads.capture_class[i][j], null_ggtt);
ads_blob_write(guc, ads.capture_instance[i][j], null_ggtt);
}
continue;
}
if (intel_guc_capture_getlistsize(guc, i,
GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
j, &size)) {
if (ads_is_mapped)
ads_blob_write(guc, ads.capture_class[i][j], null_ggtt);
goto engine_instance_list;
}
total_size += size;
if (ads_is_mapped) {
if (total_size > guc->ads_capture_size ||
intel_guc_capture_getlist(guc, i,
GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
j, &ptr)) {
ads_blob_write(guc, ads.capture_class[i][j], null_ggtt);
continue;
}
ads_blob_write(guc, ads.capture_class[i][j], ads_ggtt +
capture_offset);
iosys_map_memcpy_to(&guc->ads_map, capture_offset, ptr, size);
capture_offset += size;
}
engine_instance_list:
if (intel_guc_capture_getlistsize(guc, i,
GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
j, &size)) {
if (ads_is_mapped)
ads_blob_write(guc, ads.capture_instance[i][j], null_ggtt);
continue;
}
total_size += size;
if (ads_is_mapped) {
if (total_size > guc->ads_capture_size ||
intel_guc_capture_getlist(guc, i,
GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
j, &ptr)) {
ads_blob_write(guc, ads.capture_instance[i][j], null_ggtt);
continue;
}
ads_blob_write(guc, ads.capture_instance[i][j], ads_ggtt +
capture_offset);
iosys_map_memcpy_to(&guc->ads_map, capture_offset, ptr, size);
capture_offset += size;
}
}
if (intel_guc_capture_getlistsize(guc, i, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &size)) {
if (ads_is_mapped)
ads_blob_write(guc, ads.capture_global[i], null_ggtt);
continue;
}
total_size += size;
if (ads_is_mapped) {
if (total_size > guc->ads_capture_size ||
intel_guc_capture_getlist(guc, i, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0,
&ptr)) {
ads_blob_write(guc, ads.capture_global[i], null_ggtt);
continue;
}
ads_blob_write(guc, ads.capture_global[i], ads_ggtt + capture_offset);
iosys_map_memcpy_to(&guc->ads_map, capture_offset, ptr, size);
capture_offset += size;
}
} }
if (guc->ads_capture_size && guc->ads_capture_size != PAGE_ALIGN(total_size))
drm_warn(&i915->drm, "GuC->ADS->Capture alloc size changed from %d to %d\n",
guc->ads_capture_size, PAGE_ALIGN(total_size));
return PAGE_ALIGN(total_size);
} }
static void __guc_ads_init(struct intel_guc *guc) static void __guc_ads_init(struct intel_guc *guc)
...@@ -666,8 +761,8 @@ static void __guc_ads_init(struct intel_guc *guc) ...@@ -666,8 +761,8 @@ static void __guc_ads_init(struct intel_guc *guc)
base = intel_guc_ggtt_offset(guc, guc->ads_vma); base = intel_guc_ggtt_offset(guc, guc->ads_vma);
/* Capture list for hang debug */ /* Lists for error capture debug */
guc_capture_list_init(guc); guc_capture_prep_lists(guc);
/* ADS */ /* ADS */
ads_blob_write(guc, ads.scheduler_policies, base + ads_blob_write(guc, ads.scheduler_policies, base +
...@@ -715,6 +810,12 @@ int intel_guc_ads_create(struct intel_guc *guc) ...@@ -715,6 +810,12 @@ int intel_guc_ads_create(struct intel_guc *guc)
return ret; return ret;
guc->ads_golden_ctxt_size = ret; guc->ads_golden_ctxt_size = ret;
/* Likewise the capture lists: */
ret = guc_capture_prep_lists(guc);
if (ret < 0)
return ret;
guc->ads_capture_size = ret;
/* Now the total size can be determined: */ /* Now the total size can be determined: */
size = guc_ads_blob_size(guc); size = guc_ads_blob_size(guc);
......
// SPDX-License-Identifier: MIT
/*
* Copyright © 2021-2022 Intel Corporation
*/
#include <linux/types.h>
#include <drm/drm_print.h>
#include "gt/intel_engine_regs.h"
#include "gt/intel_gt.h"
#include "gt/intel_gt_regs.h"
#include "guc_capture_fwif.h"
#include "intel_guc_capture.h"
#include "intel_guc_fwif.h"
#include "i915_drv.h"
#include "i915_memcpy.h"
#include "i915_reg.h"
/*
* Define all device tables of GuC error capture register lists
* NOTE: For engine-registers, GuC only needs the register offsets
* from the engine-mmio-base
*/
/* XE_LPD - Global */
static const struct __guc_mmio_reg_descr xe_lpd_global_regs[] = {
{ GEN12_RING_FAULT_REG, 0, 0, "GEN12_RING_FAULT_REG" }
};
/* XE_LPD - Render / Compute Per-Class */
static const struct __guc_mmio_reg_descr xe_lpd_rc_class_regs[] = {
{ EIR, 0, 0, "EIR" }
};
/* XE_LPD - Render / Compute Per-Engine-Instance */
static const struct __guc_mmio_reg_descr xe_lpd_rc_inst_regs[] = {
{ RING_HEAD(0), 0, 0, "RING_HEAD" },
{ RING_TAIL(0), 0, 0, "RING_TAIL" },
};
/* XE_LPD - Media Decode/Encode Per-Class */
static const struct __guc_mmio_reg_descr xe_lpd_vd_class_regs[] = {
};
/* XE_LPD - Media Decode/Encode Per-Engine-Instance */
static const struct __guc_mmio_reg_descr xe_lpd_vd_inst_regs[] = {
{ RING_HEAD(0), 0, 0, "RING_HEAD" },
{ RING_TAIL(0), 0, 0, "RING_TAIL" },
};
/* XE_LPD - Video Enhancement Per-Class */
static const struct __guc_mmio_reg_descr xe_lpd_vec_class_regs[] = {
};
/* XE_LPD - Video Enhancement Per-Engine-Instance */
static const struct __guc_mmio_reg_descr xe_lpd_vec_inst_regs[] = {
{ RING_HEAD(0), 0, 0, "RING_HEAD" },
{ RING_TAIL(0), 0, 0, "RING_TAIL" },
};
#define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
#define TO_GCAP_DEF_TYPE(x) (GUC_CAPTURE_LIST_TYPE_##x)
#define MAKE_REGLIST(regslist, regsowner, regstype, class) \
{ \
regslist, \
ARRAY_SIZE(regslist), \
TO_GCAP_DEF_OWNER(regsowner), \
TO_GCAP_DEF_TYPE(regstype), \
class, \
}
/* List of lists */
static const struct __guc_mmio_reg_descr_group xe_lpd_lists[] = {
MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0),
MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS),
MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS),
MAKE_REGLIST(xe_lpd_vd_class_regs, PF, ENGINE_CLASS, GUC_VIDEO_CLASS),
MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS),
MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS),
MAKE_REGLIST(xe_lpd_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEOENHANCE_CLASS),
{}
};
static const struct __guc_mmio_reg_descr_group *
guc_capture_get_device_reglist(struct intel_guc *guc)
{
struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
if (IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915) ||
IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) {
return xe_lpd_lists;
}
return NULL;
}
static const struct __guc_mmio_reg_descr_group *
guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
u32 owner, u32 type, u32 id)
{
int i;
if (!reglists)
return NULL;
for (i = 0; reglists[i].list; ++i) {
if (reglists[i].owner == owner && reglists[i].type == type &&
(reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))
return &reglists[i];
}
return NULL;
}
static const char *
__stringify_owner(u32 owner)
{
switch (owner) {
case GUC_CAPTURE_LIST_INDEX_PF:
return "PF";
case GUC_CAPTURE_LIST_INDEX_VF:
return "VF";
default:
return "unknown";
}
return "";
}
static const char *
__stringify_type(u32 type)
{
switch (type) {
case GUC_CAPTURE_LIST_TYPE_GLOBAL:
return "Global";
case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:
return "Class";
case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:
return "Instance";
default:
return "unknown";
}
return "";
}
static const char *
__stringify_engclass(u32 class)
{
switch (class) {
case GUC_RENDER_CLASS:
return "Render";
case GUC_VIDEO_CLASS:
return "Video";
case GUC_VIDEOENHANCE_CLASS:
return "VideoEnhance";
case GUC_BLITTER_CLASS:
return "Blitter";
case GUC_COMPUTE_CLASS:
return "Compute";
default:
return "unknown";
}
return "";
}
static void
guc_capture_warn_with_list_info(struct drm_i915_private *i915, char *msg,
u32 owner, u32 type, u32 classid)
{
if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)
drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers.\n", msg,
__stringify_owner(owner), __stringify_type(type));
else
drm_dbg(&i915->drm, "GuC-capture: %s for %s %s-Registers on %s-Engine\n", msg,
__stringify_owner(owner), __stringify_type(type),
__stringify_engclass(classid));
}
static int
guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
struct guc_mmio_reg *ptr, u16 num_entries)
{
u32 i = 0;
struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;
const struct __guc_mmio_reg_descr_group *match;
if (!reglists)
return -ENODEV;
match = guc_capture_get_one_list(reglists, owner, type, classid);
if (match) {
for (i = 0; i < num_entries && i < match->num_regs; ++i) {
ptr[i].offset = match->list[i].reg.reg;
ptr[i].value = 0xDEADF00D;
ptr[i].flags = match->list[i].flags;
ptr[i].mask = match->list[i].mask;
}
return 0;
}
guc_capture_warn_with_list_info(i915, "Missing register list init", owner, type,
classid);
return -ENODATA;
}
static int
guc_cap_list_num_regs(struct intel_guc_state_capture *gc, u32 owner, u32 type, u32 classid)
{
const struct __guc_mmio_reg_descr_group *match;
match = guc_capture_get_one_list(gc->reglists, owner, type, classid);
if (!match)
return 0;
return match->num_regs;
}
int
intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
size_t *size)
{
struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
struct intel_guc_state_capture *gc = guc->capture;
struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][classid];
int num_regs;
if (!gc->reglists)
return -ENODEV;
if (cache->is_valid) {
*size = cache->size;
return cache->status;
}
num_regs = guc_cap_list_num_regs(gc, owner, type, classid);
if (!num_regs) {
guc_capture_warn_with_list_info(i915, "Missing register list size",
owner, type, classid);
return -ENODATA;
}
*size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
(num_regs * sizeof(struct guc_mmio_reg)));
return 0;
}
int
intel_guc_capture_getlist(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
void **outptr)
{
struct intel_guc_state_capture *gc = guc->capture;
struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][classid];
struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
struct guc_debug_capture_list *listnode;
int ret, num_regs;
u8 *caplist, *tmp;
size_t size = 0;
if (!gc->reglists)
return -ENODEV;
if (cache->is_valid) {
*outptr = cache->ptr;
return cache->status;
}
ret = intel_guc_capture_getlistsize(guc, owner, type, classid, &size);
if (ret) {
cache->is_valid = true;
cache->ptr = NULL;
cache->size = 0;
cache->status = ret;
return ret;
}
caplist = kzalloc(size, GFP_KERNEL);
if (!caplist) {
drm_dbg(&i915->drm, "GuC-capture: failed to alloc cached caplist");
return -ENOMEM;
}
/* populate capture list header */
tmp = caplist;
num_regs = guc_cap_list_num_regs(guc->capture, owner, type, classid);
listnode = (struct guc_debug_capture_list *)tmp;
listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs);
/* populate list of register descriptor */
tmp += sizeof(struct guc_debug_capture_list);
guc_capture_list_init(guc, owner, type, classid, (struct guc_mmio_reg *)tmp, num_regs);
/* cache this list */
cache->is_valid = true;
cache->ptr = caplist;
cache->size = size;
cache->status = 0;
*outptr = caplist;
return 0;
}
int
intel_guc_capture_getnullheader(struct intel_guc *guc,
void **outptr, size_t *size)
{
struct intel_guc_state_capture *gc = guc->capture;
struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
int tmp = sizeof(u32) * 4;
void *null_header;
if (gc->ads_null_cache) {
*outptr = gc->ads_null_cache;
*size = tmp;
return 0;
}
null_header = kzalloc(tmp, GFP_KERNEL);
if (!null_header) {
drm_dbg(&i915->drm, "GuC-capture: failed to alloc cached nulllist");
return -ENOMEM;
}
gc->ads_null_cache = null_header;
*outptr = null_header;
*size = tmp;
return 0;
}
static void
guc_capture_free_ads_cache(struct intel_guc_state_capture *gc)
{
int i, j, k;
struct __guc_capture_ads_cache *cache;
for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) {
for (j = 0; j < GUC_CAPTURE_LIST_TYPE_MAX; ++j) {
for (k = 0; k < GUC_MAX_ENGINE_CLASSES; ++k) {
cache = &gc->ads_cache[i][j][k];
if (cache->is_valid)
kfree(cache->ptr);
}
}
}
kfree(gc->ads_null_cache);
}
void intel_guc_capture_destroy(struct intel_guc *guc)
{
if (!guc->capture)
return;
guc_capture_free_ads_cache(guc->capture);
kfree(guc->capture);
guc->capture = NULL;
}
int intel_guc_capture_init(struct intel_guc *guc)
{
guc->capture = kzalloc(sizeof(*guc->capture), GFP_KERNEL);
if (!guc->capture)
return -ENOMEM;
guc->capture->reglists = guc_capture_get_device_reglist(guc);
return 0;
}
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2021-2021 Intel Corporation
*/
#ifndef _INTEL_GUC_CAPTURE_H
#define _INTEL_GUC_CAPTURE_H
#include <linux/types.h>
struct guc_gt_system_info;
struct intel_guc;
int intel_guc_capture_getlist(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
void **outptr);
int intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,
size_t *size);
int intel_guc_capture_getnullheader(struct intel_guc *guc, void **outptr, size_t *size);
void intel_guc_capture_destroy(struct intel_guc *guc);
int intel_guc_capture_init(struct intel_guc *guc);
#endif /* _INTEL_GUC_CAPTURE_H */
...@@ -314,6 +314,14 @@ enum { ...@@ -314,6 +314,14 @@ enum {
GUC_CAPTURE_LIST_INDEX_MAX = 2, GUC_CAPTURE_LIST_INDEX_MAX = 2,
}; };
/*Register-types of GuC capture register lists */
enum guc_capture_type {
GUC_CAPTURE_LIST_TYPE_GLOBAL = 0,
GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,
GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,
GUC_CAPTURE_LIST_TYPE_MAX,
};
/* GuC Additional Data Struct */ /* GuC Additional Data Struct */
struct guc_ads { struct guc_ads {
struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS]; struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment