On Sat, Feb 26, 2022 at 01:55:31AM -0800, Alan Previn wrote:
Add the ability for runtime allocation and freeing of
steered register list extentions that depend on the
detected HW config fuses.

Signed-off-by: Alan Previn <alan.previn.teres.ale...@intel.com>
---
drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h |   9 +
.../gpu/drm/i915/gt/uc/intel_guc_capture.c    | 175 ++++++++++++++++--
2 files changed, 173 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h 
b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
index 858f85478636..27b89539d0d5 100644
--- a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
@@ -51,6 +51,7 @@ struct __guc_mmio_reg_descr_group {
        u32 owner; /* see enum guc_capture_owner */
        u32 type; /* see enum guc_capture_type */
        u32 engine; /* as per MAX_ENGINE_CLASS */
+       struct __guc_mmio_reg_descr *extlist; /* only used for steered 
registers */
};

/**
@@ -78,6 +79,14 @@ struct __guc_state_capture_priv {
         */
        const struct __guc_mmio_reg_descr_group *reglists;

+       /**
+        * @extlists: allocated table of steered register lists used for 
error-capture state.
+        *
+        * NOTE: steered registers have multiple instances depending on the HW 
configuration
+        * (slices or dual-sub-slices) and thus depends on HW fuses discovered 
at startup
+        */
+       struct __guc_mmio_reg_descr_group *extlists;
+
        /**
         * @ads_cache: cached register lists that is ADS format ready
         */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index fb3ca734ef97..6370943ea300 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -133,6 +133,7 @@ static const struct __guc_mmio_reg_descr empty_regs_list[] 
= {
                TO_GCAP_DEF_OWNER(regsowner), \
                TO_GCAP_DEF_TYPE(regstype), \
                class, \
+               NULL, \
        }

/* List of lists */
@@ -150,28 +151,33 @@ static const struct __guc_mmio_reg_descr_group 
xe_lpd_lists[] = {
};

static const struct __guc_mmio_reg_descr_group *
-guc_capture_get_device_reglist(struct intel_guc *guc)
+guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
+                        u32 owner, u32 type, u32 id)
{
-       struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+       int i;

-       if (IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915) ||
-           IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) {
-               return xe_lpd_lists;
+       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 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)
+static struct __guc_mmio_reg_descr_group *
+guc_capture_get_one_ext_list(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) {
+       for (i = 0; reglists[i].extlist; ++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];
@@ -180,6 +186,127 @@ guc_capture_get_one_list(const struct 
__guc_mmio_reg_descr_group *reglists,
        return NULL;
}

+static void guc_capture_free_extlists(struct __guc_mmio_reg_descr_group 
*reglists)
+{
+       int i = 0;
+
+       if (!reglists)
+               return;
+
+       while (reglists[i].extlist)
+               kfree(reglists[i++].extlist);
+}
+
+struct __ext_steer_reg {
+       const char *name;
+       i915_reg_t reg;
+};
+
+static const struct __ext_steer_reg xe_extregs[] = {
+       {"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE},
+       {"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE}
+};
+
+static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
+                          const struct __ext_steer_reg *extlist,
+                          int slice_id, int subslice_id)
+{
+       ext->reg = extlist->reg;
+       ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
+       ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);
+       ext->regname = extlist->name;
+}
+
+static int
+__alloc_ext_regs(struct __guc_mmio_reg_descr_group *newlist,
+                const struct __guc_mmio_reg_descr_group *rootlist, int 
num_regs)
+{
+       struct __guc_mmio_reg_descr *list;
+
+       list = kcalloc(num_regs, sizeof(struct __guc_mmio_reg_descr), 
GFP_KERNEL);
+       if (!list)
+               return -ENOMEM;
+
+       newlist->extlist = list;
+       newlist->num_regs = num_regs;
+       newlist->owner = rootlist->owner;
+       newlist->engine = rootlist->engine;
+       newlist->type = rootlist->type;
+
+       return 0;
+}
+
+static void
+guc_capture_alloc_steered_lists_xe_lpd(struct intel_guc *guc,
+                                      const struct __guc_mmio_reg_descr_group 
*lists)
+{
+       struct intel_gt *gt = guc_to_gt(guc);
+       struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
+       int slice, subslice, i, num_steer_regs, num_tot_regs = 0;
+       const struct __guc_mmio_reg_descr_group *list;
+       struct __guc_mmio_reg_descr_group *extlists;
+       struct __guc_mmio_reg_descr *extarray;
+       struct sseu_dev_info *sseu;
+
+       /* In XE_LPD we only have steered registers for the render-class */
+       list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
+                                       GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, 
GUC_RENDER_CLASS);
+       /* skip if extlists was previously allocated */
+       if (!list || guc->capture.priv->extlists)
+               return;
+
+       num_steer_regs = ARRAY_SIZE(xe_extregs);
+
+       sseu = &gt->info.sseu;
+       for_each_instdone_slice_subslice(i915, sseu, slice, subslice)
+               num_tot_regs += num_steer_regs;
+
+       if (!num_tot_regs)
+               return;
+
+       /* allocate an extra for an end marker */
+       extlists = kcalloc(2, sizeof(struct __guc_mmio_reg_descr_group), 
GFP_KERNEL);
+       if (!extlists)
+               return;
+
+       if (__alloc_ext_regs(&extlists[0], list, num_tot_regs)) {
+               kfree(extlists);
+               return;
+       }
+
+       extarray = extlists[0].extlist;
+       for_each_instdone_slice_subslice(i915, sseu, slice, subslice) {
+               for (i = 0; i < num_steer_regs; ++i) {
+                       __fill_ext_reg(extarray, &xe_extregs[i], slice, 
subslice);
+                       ++extarray;
+               }
+       }
+
+       guc->capture.priv->extlists = extlists;
+}
+
+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)) {
+               /*
+                * For certain engine classes, there are slice and subslice
+                * level registers requiring steering. We allocate and populate
+                * these at init time based on hw config add it as an extension
+                * list at the end of the pre-populated render list.
+                */
+               guc_capture_alloc_steered_lists_xe_lpd(guc, xe_lpd_lists);
+               return xe_lpd_lists;
+       }
+
+       drm_warn(&i915->drm, "No GuC-capture register lists\n");
+
+       return NULL;
+}
+
static const char *
__stringify_owner(u32 owner)
{
@@ -250,10 +377,12 @@ 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;
+       u32 i = 0, j = 0;
        struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
        const struct __guc_mmio_reg_descr_group *reglists = 
guc->capture.priv->reglists;
+       struct __guc_mmio_reg_descr_group *extlists = 
guc->capture.priv->extlists;
        const struct __guc_mmio_reg_descr_group *match;
+       struct __guc_mmio_reg_descr_group *matchext;

        if (!reglists)
                return -ENODEV;
@@ -272,6 +401,17 @@ guc_capture_list_init(struct intel_guc *guc, u32 owner, 
u32 type, u32 classid,
                ptr[i].mask = match->list[i].mask;
        }

+       matchext = guc_capture_get_one_ext_list(extlists, owner, type, classid);
+       if (matchext) {
+               for (i = match->num_regs, j = 0; i < num_entries &&
+                    i < (match->num_regs + matchext->num_regs) &&
+                       j < matchext->num_regs; ++i, ++j) {
+                       ptr[i].offset = matchext->extlist[j].reg.reg;
+                       ptr[i].value = 0xDEADF00D;
+                       ptr[i].flags = matchext->extlist[j].flags;
+                       ptr[i].mask = matchext->extlist[j].mask;
+               }
+       }
        if (i < num_entries)
                drm_dbg(&i915->drm, "GuC-capture: Init reglist short %d out 
%d.\n",
                        (int)i, (int)num_entries);
@@ -283,12 +423,20 @@ static int
guc_cap_list_num_regs(struct __guc_state_capture_priv *gc, u32 owner, u32 type, 
u32 classid)
{
        const struct __guc_mmio_reg_descr_group *match;
+       struct __guc_mmio_reg_descr_group *matchext;
+       int num_regs;

        match = guc_capture_get_one_list(gc->reglists, owner, type, classid);
        if (!match)
                return 0;

-       return match->num_regs;
+       num_regs = match->num_regs;
+
+       matchext = guc_capture_get_one_ext_list(gc->extlists, owner, type, 
classid);
+       if (matchext)
+               num_regs += matchext->num_regs;
+
+       return num_regs;
}

int
@@ -408,6 +556,11 @@ void intel_guc_capture_destroy(struct intel_guc *guc)

        guc_capture_free_ads_cache(guc->capture.priv);

+       if (guc->capture.priv->extlists) {

+               guc_capture_free_extlists(guc->capture.priv->extlists);
+               kfree(guc->capture.priv->extlists);

nit: If checking for NULL reglist inside guc_capture_free_extlists, then the if condition here can be dropped. Also kfree should be unaffected either ways.

As is, this is

Reviewed-by: Umesh Nerlige Ramappa <umesh.nerlige.rama...@intel.com>

Umesh



+       }
+
        kfree(guc->capture.priv);
        guc->capture.priv = NULL;
}
--
2.25.1

Reply via email to