]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Merge tag 'drm-intel-gt-next-2024-02-15' of git://anongit.freedesktop.org/drm/drm...
authorDave Airlie <airlied@redhat.com>
Fri, 16 Feb 2024 01:19:14 +0000 (11:19 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 16 Feb 2024 01:19:15 +0000 (11:19 +1000)
UAPI Changes:

- Add GuC submission interface version query (Tvrtko Ursulin)

Driver Changes:

Fixes/improvements/new stuff:

- Atomically invalidate userptr on mmu-notifier (Jonathan Cavitt)
- Update handling of MMIO triggered reports (Umesh Nerlige Ramappa)
- Don't make assumptions about intel_wakeref_t type (Jani Nikula)
- Add workaround 14019877138 [xelpg] (Tejas Upadhyay)
- Allow for very slow HuC loading [huc] (John Harrison)
- Flush context destruction worker at suspend [guc] (Alan Previn)
- Close deregister-context race against CT-loss [guc] (Alan Previn)
- Avoid circular locking issue on busyness flush [guc] (John Harrison)
- Use rc6.supported flag from intel_gt for rc6_enable sysfs (Juan Escamilla)
- Reflect the true and current status of rc6_enable (Juan Escamilla)
- Wake GT before sending H2G message [mtl] (Vinay Belgaumkar)
- Restart the heartbeat timer when forcing a pulse (John Harrison)

Future platform enablement:

- Extend driver code of Xe_LPG to Xe_LPG+ [xelpg] (Harish Chegondi)
- Extend some workarounds/tuning to gfx version 12.74 [xelpg] (Matt Roper)

Miscellaneous:

- Reconcile Excess struct member kernel-doc warnings (Randy Dunlap)
- Change wa and EU_PERF_CNTL registers to MCR type [guc] (Shuicheng Lin)
- Add flex arrays to struct i915_syncmap (Erick Archer)
- Increasing the sleep time for live_rc6_manual [selftests] (Anirban Sk)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/Zc3iIVsiAwo+bu10@tursulin-desk
26 files changed:
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_pm.c
drivers/gpu/drm/i915/gem/i915_gem_userptr.c
drivers/gpu/drm/i915/gem/i915_gem_userptr.h [deleted file]
drivers/gpu/drm/i915/gt/gen8_engine_cs.c
drivers/gpu/drm/i915/gt/intel_engine_cs.c
drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
drivers/gpu/drm/i915/gt/intel_mocs.c
drivers/gpu/drm/i915/gt/intel_rc6.c
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/i915/gt/selftest_rc6.c
drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.h
drivers/gpu/drm/i915/gt/uc/intel_huc.c
drivers/gpu/drm/i915/gt/uc/intel_uc.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_query.c
drivers/gpu/drm/i915/i915_syncmap.c
drivers/gpu/drm/i915/intel_uncore.c
include/uapi/drm/i915_drm.h

index 555022c0652c804d55efbfa94b2d0ca5f9f97225..d3a771afb083e05272be0cf0349446604dab6505 100644 (file)
@@ -2160,12 +2160,6 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
 
 #ifdef CONFIG_MMU_NOTIFIER
        if (!err && (eb->args->flags & __EXEC_USERPTR_USED)) {
-               read_lock(&eb->i915->mm.notifier_lock);
-
-               /*
-                * count is always at least 1, otherwise __EXEC_USERPTR_USED
-                * could not have been set
-                */
                for (i = 0; i < count; i++) {
                        struct eb_vma *ev = &eb->vma[i];
                        struct drm_i915_gem_object *obj = ev->vma->obj;
@@ -2177,8 +2171,6 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
                        if (err)
                                break;
                }
-
-               read_unlock(&eb->i915->mm.notifier_lock);
        }
 #endif
 
index 0d812f4d787d7418d89d60f809d5b94179cc0133..3b27218aabe2016950fbadd49de5b8f0eb251da7 100644 (file)
@@ -28,6 +28,13 @@ void i915_gem_suspend(struct drm_i915_private *i915)
        GEM_TRACE("%s\n", dev_name(i915->drm.dev));
 
        intel_wakeref_auto(&i915->runtime_pm.userfault_wakeref, 0);
+       /*
+        * On rare occasions, we've observed the fence completion triggers
+        * free_engines asynchronously via rcu_call. Ensure those are done.
+        * This path is only called on suspend, so it's an acceptable cost.
+        */
+       rcu_barrier();
+
        flush_workqueue(i915->wq);
 
        /*
@@ -160,6 +167,9 @@ void i915_gem_suspend_late(struct drm_i915_private *i915)
         * machine in an unusable condition.
         */
 
+       /* Like i915_gem_suspend, flush tasks staged from fence triggers */
+       rcu_barrier();
+
        for_each_gt(gt, i915, i)
                intel_gt_suspend_late(gt);
 
index 1d3ebdf4069b5d0fea98aefdb2b1609f82b9650e..0e21ce9d3e5ac04377cb385a2f5a1893e8b1b19b 100644 (file)
@@ -42,7 +42,6 @@
 #include "i915_drv.h"
 #include "i915_gem_ioctls.h"
 #include "i915_gem_object.h"
-#include "i915_gem_userptr.h"
 #include "i915_scatterlist.h"
 
 #ifdef CONFIG_MMU_NOTIFIER
@@ -61,36 +60,7 @@ static bool i915_gem_userptr_invalidate(struct mmu_interval_notifier *mni,
                                        const struct mmu_notifier_range *range,
                                        unsigned long cur_seq)
 {
-       struct drm_i915_gem_object *obj = container_of(mni, struct drm_i915_gem_object, userptr.notifier);
-       struct drm_i915_private *i915 = to_i915(obj->base.dev);
-       long r;
-
-       if (!mmu_notifier_range_blockable(range))
-               return false;
-
-       write_lock(&i915->mm.notifier_lock);
-
        mmu_interval_set_seq(mni, cur_seq);
-
-       write_unlock(&i915->mm.notifier_lock);
-
-       /*
-        * We don't wait when the process is exiting. This is valid
-        * because the object will be cleaned up anyway.
-        *
-        * This is also temporarily required as a hack, because we
-        * cannot currently force non-consistent batch buffers to preempt
-        * and reschedule by waiting on it, hanging processes on exit.
-        */
-       if (current->flags & PF_EXITING)
-               return true;
-
-       /* we will unbind on next submission, still have userptr pins */
-       r = dma_resv_wait_timeout(obj->base.resv, DMA_RESV_USAGE_BOOKKEEP, false,
-                                 MAX_SCHEDULE_TIMEOUT);
-       if (r <= 0)
-               drm_err(&i915->drm, "(%ld) failed to wait for idle\n", r);
-
        return true;
 }
 
@@ -580,15 +550,3 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
 #endif
 }
 
-int i915_gem_init_userptr(struct drm_i915_private *dev_priv)
-{
-#ifdef CONFIG_MMU_NOTIFIER
-       rwlock_init(&dev_priv->mm.notifier_lock);
-#endif
-
-       return 0;
-}
-
-void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv)
-{
-}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.h b/drivers/gpu/drm/i915/gem/i915_gem_userptr.h
deleted file mode 100644 (file)
index 8dadb2f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright © 2021 Intel Corporation
- */
-
-#ifndef __I915_GEM_USERPTR_H__
-#define __I915_GEM_USERPTR_H__
-
-struct drm_i915_private;
-
-int i915_gem_init_userptr(struct drm_i915_private *dev_priv);
-void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv);
-
-#endif /* __I915_GEM_USERPTR_H__ */
index 86a04afff64b3fc76700b6d7e9793470858f11e6..e1bf13e3d307073956379da22d2d8e989b56cff6 100644 (file)
@@ -226,7 +226,7 @@ u32 *gen12_emit_aux_table_inv(struct intel_engine_cs *engine, u32 *cs)
 static int mtl_dummy_pipe_control(struct i915_request *rq)
 {
        /* Wa_14016712196 */
-       if (IS_GFX_GT_IP_RANGE(rq->engine->gt, IP_VER(12, 70), IP_VER(12, 71)) ||
+       if (IS_GFX_GT_IP_RANGE(rq->engine->gt, IP_VER(12, 70), IP_VER(12, 74)) ||
            IS_DG2(rq->i915)) {
                u32 *cs;
 
@@ -822,7 +822,7 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs)
                flags |= PIPE_CONTROL_FLUSH_L3;
 
        /* Wa_14016712196 */
-       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) || IS_DG2(i915))
+       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)) || IS_DG2(i915))
                /* dummy PIPE_CONTROL + depth flush */
                cs = gen12_emit_pipe_control(cs, 0,
                                             PIPE_CONTROL_DEPTH_CACHE_FLUSH, 0);
index 40687806d22a6dc1d1dd797f7dc64ee970517daf..1ade568ffbfa43409129228881abe60d965e8d10 100644 (file)
@@ -1190,7 +1190,8 @@ static int intel_engine_init_tlb_invalidation(struct intel_engine_cs *engine)
                        num = ARRAY_SIZE(xelpmp_regs);
                }
        } else {
-               if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 71) ||
+               if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 74) ||
+                   GRAPHICS_VER_FULL(i915) == IP_VER(12, 71) ||
                    GRAPHICS_VER_FULL(i915) == IP_VER(12, 70) ||
                    GRAPHICS_VER_FULL(i915) == IP_VER(12, 50) ||
                    GRAPHICS_VER_FULL(i915) == IP_VER(12, 55)) {
index 1a8e2b7db0138f4928482f3ce8d1b42ff5b30cc3..4ae2fa0b61dd46edc6198dcff1803c0358002196 100644 (file)
@@ -290,6 +290,9 @@ static int __intel_engine_pulse(struct intel_engine_cs *engine)
        heartbeat_commit(rq, &attr);
        GEM_BUG_ON(rq->sched.attr.priority < I915_PRIORITY_BARRIER);
 
+       /* Ensure the forced pulse gets a full period to execute */
+       next_heartbeat(engine);
+
        return 0;
 }
 
index f0dea54880af258ba607b8989b9a3d3fd712f32c..c0b2022239406dac637acff5c0da899fb6c341ee 100644 (file)
@@ -176,27 +176,13 @@ static u32 get_residency(struct intel_gt *gt, enum intel_rc6_res_type id)
        return DIV_ROUND_CLOSEST_ULL(res, 1000);
 }
 
-static u8 get_rc6_mask(struct intel_gt *gt)
-{
-       u8 mask = 0;
-
-       if (HAS_RC6(gt->i915))
-               mask |= BIT(0);
-       if (HAS_RC6p(gt->i915))
-               mask |= BIT(1);
-       if (HAS_RC6pp(gt->i915))
-               mask |= BIT(2);
-
-       return mask;
-}
-
 static ssize_t rc6_enable_show(struct kobject *kobj,
                               struct kobj_attribute *attr,
                               char *buff)
 {
        struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
 
-       return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
+       return sysfs_emit(buff, "%x\n", gt->rc6.enabled);
 }
 
 static ssize_t rc6_enable_dev_show(struct device *dev,
@@ -205,7 +191,7 @@ static ssize_t rc6_enable_dev_show(struct device *dev,
 {
        struct intel_gt *gt = intel_gt_sysfs_get_drvdata(&dev->kobj, attr->attr.name);
 
-       return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
+       return sysfs_emit(buff, "%x\n", gt->rc6.enabled);
 }
 
 static u32 __rc6_residency_ms_show(struct intel_gt *gt)
index 353f93baaca051d1c21a7fd361c43a2efa488c72..25c1023eb5f9fa5afd63fc48c3847e2a57cdaafd 100644 (file)
@@ -495,7 +495,7 @@ static unsigned int get_mocs_settings(struct drm_i915_private *i915,
        memset(table, 0, sizeof(struct drm_i915_mocs_table));
 
        table->unused_entries_index = I915_MOCS_PTE;
-       if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) {
+       if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 74))) {
                table->size = ARRAY_SIZE(mtl_mocs_table);
                table->table = mtl_mocs_table;
                table->n_entries = MTL_NUM_MOCS_ENTRIES;
index 7090e4be29cb69bb6f2fdf459cf4062fc4a1ce3a..8f4b3c8af09cce57a71bfb93a2b7d0c32ac473f8 100644 (file)
@@ -123,7 +123,7 @@ static void gen11_rc6_enable(struct intel_rc6 *rc6)
         * temporary wa and should be removed after fixing real cause
         * of forcewake timeouts.
         */
-       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)))
+       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)))
                pg_enable =
                        GEN9_MEDIA_PG_ENABLE |
                        GEN11_MEDIA_SAMPLER_PG_ENABLE;
index 3eacbc50caf8d98fd92f45640cf64a5d106c9052..91814e3abd5ce262e303e8da8a9ebbe361ed2070 100644 (file)
@@ -789,8 +789,13 @@ static void xelpg_ctx_gt_tuning_init(struct intel_engine_cs *engine,
 
        dg2_ctx_gt_tuning_init(engine, wal);
 
-       if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) ||
-           IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER))
+       /*
+        * Due to Wa_16014892111, the DRAW_WATERMARK tuning must be done in
+        * gen12_emit_indirect_ctx_rcs() rather than here on some early
+        * steppings.
+        */
+       if (!(IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) ||
+             IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)))
                wa_add(wal, DRAW_WATERMARK, VERT_WM_VAL, 0x3FF, 0, false);
 }
 
@@ -820,6 +825,9 @@ static void xelpg_ctx_workarounds_init(struct intel_engine_cs *engine,
 
        /* Wa_18019271663 */
        wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE);
+
+       /* Wa_14019877138 */
+       wa_mcr_masked_en(wal, XEHP_PSS_CHICKEN, FD_END_COLLECT);
 }
 
 static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine,
@@ -908,7 +916,7 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine,
        if (engine->class != RENDER_CLASS)
                goto done;
 
-       if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 71)))
+       if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 74)))
                xelpg_ctx_workarounds_init(engine, wal);
        else if (IS_PONTEVECCHIO(i915))
                ; /* noop; none at this time */
@@ -1643,7 +1651,7 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
 static void
 xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
 {
-       /* Wa_14018778641 / Wa_18018781329 */
+       /* Wa_14018575942 / Wa_18018781329 */
        wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB);
 
        /* Wa_22016670082 */
@@ -1710,7 +1718,7 @@ xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
  */
 static void gt_tuning_settings(struct intel_gt *gt, struct i915_wa_list *wal)
 {
-       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) {
+       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) {
                wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS);
                wa_mcr_write_or(wal, XEHP_SQCM, EN_32B_ACCESS);
        }
@@ -1743,7 +1751,7 @@ gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal)
                return;
        }
 
-       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)))
+       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)))
                xelpg_gt_workarounds_init(gt, wal);
        else if (IS_PONTEVECCHIO(i915))
                pvc_gt_workarounds_init(gt, wal);
@@ -2216,7 +2224,7 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine)
 
        if (engine->gt->type == GT_MEDIA)
                ; /* none yet */
-       else if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 71)))
+       else if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 74)))
                xelpg_whitelist_build(engine);
        else if (IS_PONTEVECCHIO(i915))
                pvc_whitelist_build(engine);
@@ -2828,7 +2836,7 @@ add_render_compute_tuning_settings(struct intel_gt *gt,
 {
        struct drm_i915_private *i915 = gt->i915;
 
-       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) || IS_DG2(i915))
+       if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)) || IS_DG2(i915))
                wa_mcr_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512);
 
        /*
@@ -2881,7 +2889,8 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li
        }
 
        if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) ||
-           IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER))
+           IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER) ||
+           IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 74), IP_VER(12, 74)))
                /* Wa_14017856879 */
                wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN3, MTL_DISABLE_FIX_FOR_EOT_FLUSH);
 
index a7189c2d660cc557c309565e9bfc69f26798e840..1aa1446c8fb09b2c5a21b3bcd3573fa58dad620e 100644 (file)
@@ -62,12 +62,12 @@ int live_rc6_manual(void *arg)
 
        dt = ktime_get();
        rc0_power = librapl_energy_uJ();
-       msleep(250);
+       msleep(1000);
        rc0_power = librapl_energy_uJ() - rc0_power;
        dt = ktime_sub(ktime_get(), dt);
        res[1] = rc6_residency(rc6);
        if ((res[1] - res[0]) >> 10) {
-               pr_err("RC6 residency increased by %lldus while disabled for 250ms!\n",
+               pr_err("RC6 residency increased by %lldus while disabled for 1000ms!\n",
                       (res[1] - res[0]) >> 10);
                err = -EINVAL;
                goto out_unlock;
index 63724e17829a746c55dd8baa6acb7fd9477e7abe..f7372f736a776028f84e552a2e5aba86829c543d 100644 (file)
@@ -377,8 +377,13 @@ static int guc_mmio_regset_init(struct temp_regset *regset,
            CCS_MASK(engine->gt))
                ret |= GUC_MMIO_REG_ADD(gt, regset, GEN12_RCU_MODE, true);
 
+       /*
+        * some of the WA registers are MCR registers. As it is safe to
+        * use MCR form for non-MCR registers, for code simplicity, all
+        * WA registers are added with MCR form.
+        */
        for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
-               ret |= GUC_MMIO_REG_ADD(gt, regset, wa->reg, wa->masked_reg);
+               ret |= GUC_MCR_REG_ADD(gt, regset, wa->mcr_reg, wa->masked_reg);
 
        /* Be extra paranoid and include all whitelist registers. */
        for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++)
@@ -394,13 +399,13 @@ static int guc_mmio_regset_init(struct temp_regset *regset,
                        ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false);
 
        if (GRAPHICS_VER(engine->i915) >= 12) {
-               ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL0, false);
-               ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL1, false);
-               ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL2, false);
-               ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL3, false);
-               ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL4, false);
-               ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL5, false);
-               ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL6, false);
+               ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL0)), false);
+               ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL1)), false);
+               ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL2)), false);
+               ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL3)), false);
+               ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL4)), false);
+               ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL5)), false);
+               ret |= GUC_MCR_REG_ADD(gt, regset, MCR_REG(i915_mmio_reg_offset(EU_PERF_CNTL6)), false);
        }
 
        return ret ? -1 : 0;
index 0f79cb658518268efec6e0244307f0698dad4ed3..52332bb143395e80b362a0ba91386b8eef5f7d41 100644 (file)
@@ -184,7 +184,7 @@ static int guc_wait_ucode(struct intel_guc *guc)
         * in the seconds range. However, there is a limit on how long an
         * individual wait_for() can wait. So wrap it in a loop.
         */
-       before_freq = intel_rps_read_actual_frequency(&uncore->gt->rps);
+       before_freq = intel_rps_read_actual_frequency(&gt->rps);
        before = ktime_get();
        for (count = 0; count < GUC_LOAD_RETRY_LIMIT; count++) {
                ret = wait_for(guc_load_done(uncore, &status, &success), 1000);
@@ -192,7 +192,7 @@ static int guc_wait_ucode(struct intel_guc *guc)
                        break;
 
                guc_dbg(guc, "load still in progress, count = %d, freq = %dMHz, status = 0x%08X [0x%02X/%02X]\n",
-                       count, intel_rps_read_actual_frequency(&uncore->gt->rps), status,
+                       count, intel_rps_read_actual_frequency(&gt->rps), status,
                        REG_FIELD_GET(GS_BOOTROM_MASK, status),
                        REG_FIELD_GET(GS_UKERNEL_MASK, status));
        }
@@ -204,7 +204,7 @@ static int guc_wait_ucode(struct intel_guc *guc)
                u32 bootrom = REG_FIELD_GET(GS_BOOTROM_MASK, status);
 
                guc_info(guc, "load failed: status = 0x%08X, time = %lldms, freq = %dMHz, ret = %d\n",
-                        status, delta_ms, intel_rps_read_actual_frequency(&uncore->gt->rps), ret);
+                        status, delta_ms, intel_rps_read_actual_frequency(&gt->rps), ret);
                guc_info(guc, "load failed: status: Reset = %d, BootROM = 0x%02X, UKernel = 0x%02X, MIA = 0x%02X, Auth = 0x%02X\n",
                         REG_FIELD_GET(GS_MIA_IN_RESET, status),
                         bootrom, ukernel,
@@ -254,11 +254,11 @@ static int guc_wait_ucode(struct intel_guc *guc)
                guc_warn(guc, "excessive init time: %lldms! [status = 0x%08X, count = %d, ret = %d]\n",
                         delta_ms, status, count, ret);
                guc_warn(guc, "excessive init time: [freq = %dMHz, before = %dMHz, perf_limit_reasons = 0x%08X]\n",
-                        intel_rps_read_actual_frequency(&uncore->gt->rps), before_freq,
+                        intel_rps_read_actual_frequency(&gt->rps), before_freq,
                         intel_uncore_read(uncore, intel_gt_perf_limit_reasons_reg(gt)));
        } else {
                guc_dbg(guc, "init took %lldms, freq = %dMHz, before = %dMHz, status = 0x%08X, count = %d, ret = %d\n",
-                       delta_ms, intel_rps_read_actual_frequency(&uncore->gt->rps),
+                       delta_ms, intel_rps_read_actual_frequency(&gt->rps),
                        before_freq, status, count, ret);
        }
 
index a259f1118c5ab1f660d506e4719a8b54a7a6fcc8..f3dcae4b9d455ed37d3cc3fd1635760cd9e264af 100644 (file)
@@ -236,6 +236,13 @@ set_context_destroyed(struct intel_context *ce)
        ce->guc_state.sched_state |= SCHED_STATE_DESTROYED;
 }
 
+static inline void
+clr_context_destroyed(struct intel_context *ce)
+{
+       lockdep_assert_held(&ce->guc_state.lock);
+       ce->guc_state.sched_state &= ~SCHED_STATE_DESTROYED;
+}
+
 static inline bool context_pending_disable(struct intel_context *ce)
 {
        return ce->guc_state.sched_state & SCHED_STATE_PENDING_DISABLE;
@@ -613,6 +620,8 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc,
                                         u32 g2h_len_dw,
                                         bool loop)
 {
+       int ret;
+
        /*
         * We always loop when a send requires a reply (i.e. g2h_len_dw > 0),
         * so we don't handle the case where we don't get a reply because we
@@ -623,7 +632,11 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc,
        if (g2h_len_dw)
                atomic_inc(&guc->outstanding_submission_g2h);
 
-       return intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop);
+       ret = intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop);
+       if (ret)
+               atomic_dec(&guc->outstanding_submission_g2h);
+
+       return ret;
 }
 
 int intel_guc_wait_for_pending_msg(struct intel_guc *guc,
@@ -1362,7 +1375,45 @@ static void guc_enable_busyness_worker(struct intel_guc *guc)
 
 static void guc_cancel_busyness_worker(struct intel_guc *guc)
 {
-       cancel_delayed_work_sync(&guc->timestamp.work);
+       /*
+        * There are many different call stacks that can get here. Some of them
+        * hold the reset mutex. The busyness worker also attempts to acquire the
+        * reset mutex. Synchronously flushing a worker thread requires acquiring
+        * the worker mutex. Lockdep sees this as a conflict. It thinks that the
+        * flush can deadlock because it holds the worker mutex while waiting for
+        * the reset mutex, but another thread is holding the reset mutex and might
+        * attempt to use other worker functions.
+        *
+        * In practice, this scenario does not exist because the busyness worker
+        * does not block waiting for the reset mutex. It does a try-lock on it and
+        * immediately exits if the lock is already held. Unfortunately, the mutex
+        * in question (I915_RESET_BACKOFF) is an i915 implementation which has lockdep
+        * annotation but not to the extent of explaining the 'might lock' is also a
+        * 'does not need to lock'. So one option would be to add more complex lockdep
+        * annotations to ignore the issue (if at all possible). A simpler option is to
+        * just not flush synchronously when a rest in progress. Given that the worker
+        * will just early exit and re-schedule itself anyway, there is no advantage
+        * to running it immediately.
+        *
+        * If a reset is not in progress, then the synchronous flush may be required.
+        * As noted many call stacks lead here, some during suspend and driver unload
+        * which do require a synchronous flush to make sure the worker is stopped
+        * before memory is freed.
+        *
+        * Trying to pass a 'need_sync' or 'in_reset' flag all the way down through
+        * every possible call stack is unfeasible. It would be too intrusive to many
+        * areas that really don't care about the GuC backend. However, there is the
+        * 'reset_in_progress' flag available, so just use that.
+        *
+        * And note that in the case of a reset occurring during driver unload
+        * (wedge_on_fini), skipping the cancel in _prepare (when the reset flag is set
+        * is fine because there is another cancel in _finish (when the reset flag is
+        * not).
+        */
+       if (guc_to_gt(guc)->uc.reset_in_progress)
+               cancel_delayed_work(&guc->timestamp.work);
+       else
+               cancel_delayed_work_sync(&guc->timestamp.work);
 }
 
 static void __reset_guc_busyness_stats(struct intel_guc *guc)
@@ -1613,6 +1664,11 @@ static void guc_flush_submissions(struct intel_guc *guc)
        spin_unlock_irqrestore(&sched_engine->lock, flags);
 }
 
+void intel_guc_submission_flush_work(struct intel_guc *guc)
+{
+       flush_work(&guc->submission_state.destroyed_worker);
+}
+
 static void guc_flush_destroyed_contexts(struct intel_guc *guc);
 
 void intel_guc_submission_reset_prepare(struct intel_guc *guc)
@@ -1948,8 +2004,16 @@ void intel_guc_submission_cancel_requests(struct intel_guc *guc)
 
 void intel_guc_submission_reset_finish(struct intel_guc *guc)
 {
+       /*
+        * Ensure the busyness worker gets cancelled even on a fatal wedge.
+        * Note that reset_prepare is not allowed to because it confuses lockdep.
+        */
+       if (guc_submission_initialized(guc))
+               guc_cancel_busyness_worker(guc);
+
        /* Reset called during driver load or during wedge? */
        if (unlikely(!guc_submission_initialized(guc) ||
+                    !intel_guc_is_fw_running(guc) ||
                     intel_gt_is_wedged(guc_to_gt(guc)))) {
                return;
        }
@@ -3283,12 +3347,13 @@ static void guc_context_close(struct intel_context *ce)
        spin_unlock_irqrestore(&ce->guc_state.lock, flags);
 }
 
-static inline void guc_lrc_desc_unpin(struct intel_context *ce)
+static inline int guc_lrc_desc_unpin(struct intel_context *ce)
 {
        struct intel_guc *guc = ce_to_guc(ce);
        struct intel_gt *gt = guc_to_gt(guc);
        unsigned long flags;
        bool disabled;
+       int ret;
 
        GEM_BUG_ON(!intel_gt_pm_is_awake(gt));
        GEM_BUG_ON(!ctx_id_mapped(guc, ce->guc_id.id));
@@ -3299,18 +3364,41 @@ static inline void guc_lrc_desc_unpin(struct intel_context *ce)
        spin_lock_irqsave(&ce->guc_state.lock, flags);
        disabled = submission_disabled(guc);
        if (likely(!disabled)) {
+               /*
+                * Take a gt-pm ref and change context state to be destroyed.
+                * NOTE: a G2H IRQ that comes after will put this gt-pm ref back
+                */
                __intel_gt_pm_get(gt);
                set_context_destroyed(ce);
                clr_context_registered(ce);
        }
        spin_unlock_irqrestore(&ce->guc_state.lock, flags);
+
        if (unlikely(disabled)) {
                release_guc_id(guc, ce);
                __guc_context_destroy(ce);
-               return;
+               return 0;
        }
 
-       deregister_context(ce, ce->guc_id.id);
+       /*
+        * GuC is active, lets destroy this context, but at this point we can still be racing
+        * with suspend, so we undo everything if the H2G fails in deregister_context so
+        * that GuC reset will find this context during clean up.
+        */
+       ret = deregister_context(ce, ce->guc_id.id);
+       if (ret) {
+               spin_lock(&ce->guc_state.lock);
+               set_context_registered(ce);
+               clr_context_destroyed(ce);
+               spin_unlock(&ce->guc_state.lock);
+               /*
+                * As gt-pm is awake at function entry, intel_wakeref_put_async merely decrements
+                * the wakeref immediately but per function spec usage call this after unlock.
+                */
+               intel_wakeref_put_async(&gt->wakeref);
+       }
+
+       return ret;
 }
 
 static void __guc_context_destroy(struct intel_context *ce)
@@ -3378,7 +3466,22 @@ static void deregister_destroyed_contexts(struct intel_guc *guc)
                if (!ce)
                        break;
 
-               guc_lrc_desc_unpin(ce);
+               if (guc_lrc_desc_unpin(ce)) {
+                       /*
+                        * This means GuC's CT link severed mid-way which could happen
+                        * in suspend-resume corner cases. In this case, put the
+                        * context back into the destroyed_contexts list which will
+                        * get picked up on the next context deregistration event or
+                        * purged in a GuC sanitization event (reset/unload/wedged/...).
+                        */
+                       spin_lock_irqsave(&guc->submission_state.lock, flags);
+                       list_add_tail(&ce->destroyed_link,
+                                     &guc->submission_state.destroyed_contexts);
+                       spin_unlock_irqrestore(&guc->submission_state.lock, flags);
+                       /* Bail now since the list might never be emptied if h2gs fail */
+                       break;
+               }
+
        }
 }
 
@@ -3389,6 +3492,17 @@ static void destroyed_worker_func(struct work_struct *w)
        struct intel_gt *gt = guc_to_gt(guc);
        intel_wakeref_t wakeref;
 
+       /*
+        * In rare cases we can get here via async context-free fence-signals that
+        * come very late in suspend flow or very early in resume flows. In these
+        * cases, GuC won't be ready but just skipping it here is fine as these
+        * pending-destroy-contexts get destroyed totally at GuC reset time at the
+        * end of suspend.. OR.. this worker can be picked up later on the next
+        * context destruction trigger after resume-completes
+        */
+       if (!intel_guc_is_ready(guc))
+               return;
+
        with_intel_gt_pm(gt, wakeref)
                deregister_destroyed_contexts(guc);
 }
index c57b29cdb1a64eeb2057101e7d59d0ec761d74c9..b6df75622d3b9fa777ebb6f7a4f4cc8a285cd6f9 100644 (file)
@@ -38,6 +38,8 @@ int intel_guc_wait_for_pending_msg(struct intel_guc *guc,
                                   bool interruptible,
                                   long timeout);
 
+void intel_guc_submission_flush_work(struct intel_guc *guc);
+
 static inline bool intel_guc_submission_is_supported(struct intel_guc *guc)
 {
        return guc->submission_supported;
index ba9e07fc2b57706d658ddc46eb46dd706842e310..0945b177d5f975f403c9133ba9e59a978bd307b5 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 
 #include "gt/intel_gt.h"
+#include "gt/intel_rps.h"
 #include "intel_guc_reg.h"
 #include "intel_huc.h"
 #include "intel_huc_print.h"
@@ -447,17 +448,68 @@ static const char *auth_mode_string(struct intel_huc *huc,
        return partial ? "clear media" : "all workloads";
 }
 
+/*
+ * Use a longer timeout for debug builds so that problems can be detected
+ * and analysed. But a shorter timeout for releases so that user's don't
+ * wait forever to find out there is a problem. Note that the only reason
+ * an end user should hit the timeout is in case of extreme thermal throttling.
+ * And a system that is that hot during boot is probably dead anyway!
+ */
+#if defined(CONFIG_DRM_I915_DEBUG_GEM)
+#define HUC_LOAD_RETRY_LIMIT   20
+#else
+#define HUC_LOAD_RETRY_LIMIT   3
+#endif
+
 int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
                                     enum intel_huc_authentication_type type)
 {
        struct intel_gt *gt = huc_to_gt(huc);
-       int ret;
+       struct intel_uncore *uncore = gt->uncore;
+       ktime_t before, after, delta;
+       int ret, count;
+       u64 delta_ms;
+       u32 before_freq;
 
-       ret = __intel_wait_for_register(gt->uncore,
-                                       huc->status[type].reg,
-                                       huc->status[type].mask,
-                                       huc->status[type].value,
-                                       2, 50, NULL);
+       /*
+        * The KMD requests maximum frequency during driver load, however thermal
+        * throttling can force the frequency down to minimum (although the board
+        * really should never get that hot in real life!). IFWI  issues have been
+        * seen to cause sporadic failures to grant the higher frequency. And at
+        * minimum frequency, the authentication time can be in the seconds range.
+        * Note that there is a limit on how long an individual wait_for() can wait.
+        * So wrap it in a loop.
+        */
+       before_freq = intel_rps_read_actual_frequency(&gt->rps);
+       before = ktime_get();
+       for (count = 0; count < HUC_LOAD_RETRY_LIMIT; count++) {
+               ret = __intel_wait_for_register(gt->uncore,
+                                               huc->status[type].reg,
+                                               huc->status[type].mask,
+                                               huc->status[type].value,
+                                               2, 1000, NULL);
+               if (!ret)
+                       break;
+
+               huc_dbg(huc, "auth still in progress, count = %d, freq = %dMHz, status = 0x%08X\n",
+                       count, intel_rps_read_actual_frequency(&gt->rps),
+                       huc->status[type].reg.reg);
+       }
+       after = ktime_get();
+       delta = ktime_sub(after, before);
+       delta_ms = ktime_to_ms(delta);
+
+       if (delta_ms > 50) {
+               huc_warn(huc, "excessive auth time: %lldms! [status = 0x%08X, count = %d, ret = %d]\n",
+                        delta_ms, huc->status[type].reg.reg, count, ret);
+               huc_warn(huc, "excessive auth time: [freq = %dMHz, before = %dMHz, perf_limit_reasons = 0x%08X]\n",
+                        intel_rps_read_actual_frequency(&gt->rps), before_freq,
+                        intel_uncore_read(uncore, intel_gt_perf_limit_reasons_reg(gt)));
+       } else {
+               huc_dbg(huc, "auth took %lldms, freq = %dMHz, before = %dMHz, status = 0x%08X, count = %d, ret = %d\n",
+                       delta_ms, intel_rps_read_actual_frequency(&gt->rps),
+                       before_freq, huc->status[type].reg.reg, count, ret);
+       }
 
        /* mark the load process as complete even if the wait failed */
        delayed_huc_load_complete(huc);
index 3872d309ed31fa6a313bd7d0d72f3e5ccde679ec..6dfe5d9456c69e06987be23367c243bb1f8f908e 100644 (file)
@@ -640,7 +640,7 @@ void intel_uc_reset_finish(struct intel_uc *uc)
        uc->reset_in_progress = false;
 
        /* Firmware expected to be running when this function is called */
-       if (intel_guc_is_fw_running(guc) && intel_uc_uses_guc_submission(uc))
+       if (intel_uc_uses_guc_submission(uc))
                intel_guc_submission_reset_finish(guc);
 }
 
@@ -690,6 +690,8 @@ void intel_uc_suspend(struct intel_uc *uc)
                return;
        }
 
+       intel_guc_submission_flush_work(guc);
+
        with_intel_runtime_pm(&uc_to_gt(uc)->i915->runtime_pm, wakeref) {
                err = intel_guc_suspend(guc);
                if (err)
index db99c2ef66db84726129c9fba1926730ad753472..990eaa029d9c258935f5bb256be97f424ae6f44c 100644 (file)
@@ -147,7 +147,7 @@ static const char *i915_cache_level_str(struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *i915 = obj_to_i915(obj);
 
-       if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) {
+       if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 74))) {
                switch (obj->pat_index) {
                case 0: return " WB";
                case 1: return " WT";
index 861567362abd105c835c3d357f5d8cc2f0954998..e81b3b2858acccd3146fb9de2b93a897c511bf96 100644 (file)
@@ -165,14 +165,6 @@ struct i915_gem_mm {
        struct notifier_block vmap_notifier;
        struct shrinker *shrinker;
 
-#ifdef CONFIG_MMU_NOTIFIER
-       /**
-        * notifier_lock for mmu notifiers, memory may not be allocated
-        * while holding this lock.
-        */
-       rwlock_t notifier_lock;
-#endif
-
        /* shrinker accounting, also useful for userland debugging */
        u64 shrink_memory;
        u32 shrink_count;
index 92758b6b41f011376d1f8cdf7ca1456d22b89f5e..1391c01d7663ee0d938b58cb32184b7f561d3d58 100644 (file)
@@ -48,7 +48,6 @@
 #include "gem/i915_gem_object_frontbuffer.h"
 #include "gem/i915_gem_pm.h"
 #include "gem/i915_gem_region.h"
-#include "gem/i915_gem_userptr.h"
 #include "gt/intel_engine_user.h"
 #include "gt/intel_gt.h"
 #include "gt/intel_gt_pm.h"
@@ -1165,10 +1164,6 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
        if (intel_vgpu_active(dev_priv) && !intel_vgpu_has_huge_gtt(dev_priv))
                RUNTIME_INFO(dev_priv)->page_sizes = I915_GTT_PAGE_SIZE_4K;
 
-       ret = i915_gem_init_userptr(dev_priv);
-       if (ret)
-               return ret;
-
        for_each_gt(gt, dev_priv, i) {
                intel_uc_fetch_firmwares(&gt->uc);
                intel_wopcm_init(&gt->wopcm);
index 2d695818f0062bc24819f89607e4964c58ae8804..bd9d812b1afa77ee02cd0324875157fe858e6a8a 100644 (file)
@@ -3225,7 +3225,7 @@ u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915)
        struct intel_gt *gt = to_gt(i915);
 
        /* Wa_18013179988 */
-       if (IS_DG2(i915) || IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) {
+       if (IS_DG2(i915) || IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) {
                intel_wakeref_t wakeref;
                u32 reg, shift;
 
index fa3e937ed3f5ab20ed4040bad1257a035d0c5d5d..3baa2f54a86ed8aa246381b858d3a513365c5694 100644 (file)
@@ -551,6 +551,38 @@ static int query_hwconfig_blob(struct drm_i915_private *i915,
        return hwconfig->size;
 }
 
+static int
+query_guc_submission_version(struct drm_i915_private *i915,
+                            struct drm_i915_query_item *query)
+{
+       struct drm_i915_query_guc_submission_version __user *query_ptr =
+                                           u64_to_user_ptr(query->data_ptr);
+       struct drm_i915_query_guc_submission_version ver;
+       struct intel_guc *guc = &to_gt(i915)->uc.guc;
+       const size_t size = sizeof(ver);
+       int ret;
+
+       if (!intel_uc_uses_guc_submission(&to_gt(i915)->uc))
+               return -ENODEV;
+
+       ret = copy_query_item(&ver, size, size, query);
+       if (ret != 0)
+               return ret;
+
+       if (ver.branch || ver.major || ver.minor || ver.patch)
+               return -EINVAL;
+
+       ver.branch = 0;
+       ver.major = guc->submission_version.major;
+       ver.minor = guc->submission_version.minor;
+       ver.patch = guc->submission_version.patch;
+
+       if (copy_to_user(query_ptr, &ver, size))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv,
                                        struct drm_i915_query_item *query_item) = {
        query_topology_info,
@@ -559,6 +591,7 @@ static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv,
        query_memregion_info,
        query_hwconfig_blob,
        query_geometry_subslices,
+       query_guc_submission_version,
 };
 
 int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
index 60404dbb2e9fa9f3484989cdfe34bacd202d0ca9..df6437c37373df20f6a93b71887eb82a015757bd 100644 (file)
@@ -75,13 +75,10 @@ struct i915_syncmap {
        unsigned int height;
        unsigned int bitmap;
        struct i915_syncmap *parent;
-       /*
-        * Following this header is an array of either seqno or child pointers:
-        * union {
-        *      u32 seqno[KSYNCMAP];
-        *      struct i915_syncmap *child[KSYNCMAP];
-        * };
-        */
+       union {
+               DECLARE_FLEX_ARRAY(u32, seqno);
+               DECLARE_FLEX_ARRAY(struct i915_syncmap *, child);
+       };
 };
 
 /**
@@ -99,13 +96,13 @@ void i915_syncmap_init(struct i915_syncmap **root)
 static inline u32 *__sync_seqno(struct i915_syncmap *p)
 {
        GEM_BUG_ON(p->height);
-       return (u32 *)(p + 1);
+       return p->seqno;
 }
 
 static inline struct i915_syncmap **__sync_child(struct i915_syncmap *p)
 {
        GEM_BUG_ON(!p->height);
-       return (struct i915_syncmap **)(p + 1);
+       return p->child;
 }
 
 static inline unsigned int
@@ -200,7 +197,7 @@ __sync_alloc_leaf(struct i915_syncmap *parent, u64 id)
 {
        struct i915_syncmap *p;
 
-       p = kmalloc(sizeof(*p) + KSYNCMAP * sizeof(u32), GFP_KERNEL);
+       p = kmalloc(struct_size(p, seqno, KSYNCMAP), GFP_KERNEL);
        if (unlikely(!p))
                return NULL;
 
@@ -282,7 +279,7 @@ static noinline int __sync_set(struct i915_syncmap **root, u64 id, u32 seqno)
                        unsigned int above;
 
                        /* Insert a join above the current layer */
-                       next = kzalloc(sizeof(*next) + KSYNCMAP * sizeof(next),
+                       next = kzalloc(struct_size(next, child, KSYNCMAP),
                                       GFP_KERNEL);
                        if (unlikely(!next))
                                return -ENOMEM;
index dfefad5a5fec9e6fd1da6dd9bf9ec64905d8e958..76400e9c40f056a2059967b5cf960adbac112bd5 100644 (file)
@@ -1800,7 +1800,10 @@ static const struct intel_forcewake_range __mtl_fw_ranges[] = {
        GEN_FW_RANGE(0x24000, 0x2ffff, 0), /*
                0x24000 - 0x2407f: always on
                0x24080 - 0x2ffff: reserved */
-       GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT)
+       GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT),
+       GEN_FW_RANGE(0x40000, 0x1901ef, 0),
+       GEN_FW_RANGE(0x1901f0, 0x1901f3, FORCEWAKE_GT)
+               /* FIXME: WA to wake GT while triggering H2G */
 };
 
 /*
index fd4f9574d177a269b2cdbe5a36b3b30f2addbc94..bd87386a82438500d9263a7d2193496b94f3500c 100644 (file)
@@ -3013,6 +3013,7 @@ struct drm_i915_query_item {
         *  - %DRM_I915_QUERY_MEMORY_REGIONS (see struct drm_i915_query_memory_regions)
         *  - %DRM_I915_QUERY_HWCONFIG_BLOB (see `GuC HWCONFIG blob uAPI`)
         *  - %DRM_I915_QUERY_GEOMETRY_SUBSLICES (see struct drm_i915_query_topology_info)
+        *  - %DRM_I915_QUERY_GUC_SUBMISSION_VERSION (see struct drm_i915_query_guc_submission_version)
         */
        __u64 query_id;
 #define DRM_I915_QUERY_TOPOLOGY_INFO           1
@@ -3021,6 +3022,7 @@ struct drm_i915_query_item {
 #define DRM_I915_QUERY_MEMORY_REGIONS          4
 #define DRM_I915_QUERY_HWCONFIG_BLOB           5
 #define DRM_I915_QUERY_GEOMETRY_SUBSLICES      6
+#define DRM_I915_QUERY_GUC_SUBMISSION_VERSION  7
 /* Must be kept compact -- no holes and well documented */
 
        /**
@@ -3566,6 +3568,16 @@ struct drm_i915_query_memory_regions {
        struct drm_i915_memory_region_info regions[];
 };
 
+/**
+ * struct drm_i915_query_guc_submission_version - query GuC submission interface version
+ */
+struct drm_i915_query_guc_submission_version {
+       __u32 branch;
+       __u32 major;
+       __u32 minor;
+       __u32 patch;
+};
+
 /**
  * DOC: GuC HWCONFIG blob uAPI
  *