From 6cb304b31293844461437fe76dc308aaffe31dc8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 15 Sep 2020 11:51:13 +0100 Subject: drm/i915/gt: Check for a registered driver with IPS If the ips module calls into the driver during an unbind/bind cycle, we may see the driver while it has unregistered itself from ips and try and dereference a NULL ips_mchdev pointer. <1> [211.928844] BUG: kernel NULL pointer dereference, address: 0000000000000014 <1> [211.928861] #PF: supervisor read access in kernel mode <1> [211.928871] #PF: error_code(0x0000) - not-present page <6> [211.928881] PGD 0 P4D 0 <4> [211.928890] Oops: 0000 [#1] PREEMPT SMP PTI <4> [211.928900] CPU: 3 PID: 327 Comm: ips-monitor Not tainted 5.9.0-rc5-CI-CI_DRM_9008+ #1 <4> [211.928914] Hardware name: Hewlett-Packard HP EliteBook 8440p/172A, BIOS 68CCU Ver. F.24 09/13/2013 <4> [211.929056] RIP: 0010:mchdev_get+0x5a/0x180 [i915] <4> [211.929067] Code: c0 5a 74 0d 80 3d f1 53 29 00 00 0f 84 ab 00 00 00 48 8b 1d c8 a8 29 00 e8 d3 18 89 e1 85 c0 74 09 80 3d d1 53 29 00 00 74 65 <8b> 4b 14 48 8d 7b 14 85 c9 0f 84 09 01 00 00 8d 51 01 89 c8 f0 0f <4> [211.929095] RSP: 0018:ffffc900002efe60 EFLAGS: 00010202 <4> [211.929105] RAX: 0000000000000001 RBX: 0000000000000000 RCX: ffff8881297acf40 <4> [211.929118] RDX: 0000000000000000 RSI: ffffffff8264e2c0 RDI: ffff8881297ad820 <4> [211.929130] RBP: ffffc900002efe68 R08: ffff8881297ad820 R09: 00000000fffffffe <4> [211.929143] R10: ffff8881297acf40 R11: 00000000fff74c96 R12: ffff8881294dfa18 <4> [211.929155] R13: 0000000000000067 R14: ffff888126eff640 R15: ffff888126efe840 <4> [211.929168] FS: 0000000000000000(0000) GS:ffff888133d80000(0000) knlGS:0000000000000000 <4> [211.929182] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4> [211.929194] CR2: 0000000000000014 CR3: 0000000002610000 CR4: 00000000000006e0 <4> [211.929206] Call Trace: <4> [211.929294] i915_read_mch_val+0x15/0x380 [i915] <4> [211.929309] ? ips_monitor+0x3fb/0x630 [intel_ips] <4> [211.929321] ips_monitor+0x53c/0x630 [intel_ips] <4> [211.929334] ? ips_gpu_lower+0x30/0x30 [intel_ips] <4> [211.929348] kthread+0x14d/0x170 <4> [211.929358] ? kthread_park+0x80/0x80 <4> [211.929369] ret_from_fork+0x22/0x30 <4> [211.929382] Modules linked in: vgem snd_hda_codec_hdmi snd_hda_codec_generic ledtrig_audio i915 coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_intel snd_intel_dspcfg snd_hda_codec snd_hwdep snd_hda_core e1000e snd_pcm mei_me mei intel_ips lpc_ich ptp prime_numbers pps_core <4> [211.929437] CR2: 0000000000000014 Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20200915105113.26564-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/gt/intel_rps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/gt/intel_rps.c') diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index e6a00eea0631..a53928363b86 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1949,7 +1949,7 @@ static struct drm_i915_private *mchdev_get(void) rcu_read_lock(); i915 = rcu_dereference(ips_mchdev); - if (!kref_get_unless_zero(&i915->drm.ref)) + if (i915 && !kref_get_unless_zero(&i915->drm.ref)) i915 = NULL; rcu_read_unlock(); -- cgit v1.2.3 From e82351e74dcfc76c0f4241b5dbf8ee7c0ceb22be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 21 Oct 2020 16:14:40 +0300 Subject: drm/i915: Read actual GPU frequency from MEMSTAT_ILK on ILK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no GEN6_RPSTAT1 on ILK. Instead of reading that let's try to get the same information from MEMSTAT_ILK. At least it seems to track MEMSWCTL frequency request perfectly on my ILK. It needs the same invert trick as the request value. We don't want to put the invert thing into intel_gpu_freq() and intel_freq_opcode() because that would incorrectly invert the min/max/etc frequencies also. One day someone might want to reverse engineer the formula for converting these numbers to Hz, but for now we'll just report them raw. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20201021131443.25616-2-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/gt/intel_rps.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915/gt/intel_rps.c') diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index e6a00eea0631..e2d7ef5f6dc9 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -390,6 +390,16 @@ static void gen5_rps_update(struct intel_rps *rps) spin_unlock_irq(&mchdev_lock); } +static unsigned int gen5_invert_freq(struct intel_rps *rps, + unsigned int val) +{ + /* Invert the frequency bin into an ips delay */ + val = rps->max_freq - val; + val = rps->min_freq + val; + + return val; +} + static bool gen5_rps_set(struct intel_rps *rps, u8 val) { struct intel_uncore *uncore = rps_to_uncore(rps); @@ -404,8 +414,7 @@ static bool gen5_rps_set(struct intel_rps *rps, u8 val) } /* Invert the frequency bin into an ips delay */ - val = rps->max_freq - val; - val = rps->min_freq + val; + val = gen5_invert_freq(rps, val); rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | @@ -1432,8 +1441,10 @@ int intel_gpu_freq(struct intel_rps *rps, int val) return chv_gpu_freq(rps, val); else if (IS_VALLEYVIEW(i915)) return byt_gpu_freq(rps, val); - else + else if (INTEL_GEN(i915) >= 6) return val * GT_FREQUENCY_MULTIPLIER; + else + return val; } int intel_freq_opcode(struct intel_rps *rps, int val) @@ -1447,8 +1458,10 @@ int intel_freq_opcode(struct intel_rps *rps, int val) return chv_freq_opcode(rps, val); else if (IS_VALLEYVIEW(i915)) return byt_freq_opcode(rps, val); - else + else if (INTEL_GEN(i915) >= 6) return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER); + else + return val; } static void vlv_init_gpll_ref_freq(struct intel_rps *rps) @@ -1864,8 +1877,11 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat) cagf = (rpstat & GEN9_CAGF_MASK) >> GEN9_CAGF_SHIFT; else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT; - else + else if (INTEL_GEN(i915) >= 6) cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT; + else + cagf = gen5_invert_freq(rps, (rpstat & MEMSTAT_PSTATE_MASK) >> + MEMSTAT_PSTATE_SHIFT); return cagf; } @@ -1873,14 +1889,17 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat) static u32 read_cagf(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); + struct intel_uncore *uncore = rps_to_uncore(rps); u32 freq; if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { vlv_punit_get(i915); freq = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS); vlv_punit_put(i915); + } else if (INTEL_GEN(i915) >= 6) { + freq = intel_uncore_read(uncore, GEN6_RPSTAT1); } else { - freq = intel_uncore_read(rps_to_uncore(rps), GEN6_RPSTAT1); + freq = intel_uncore_read(uncore, MEMSTAT_ILK); } return intel_rps_get_cagf(rps, freq); -- cgit v1.2.3 From d08c4e2327428d93f6d80ab0e7a79679f4c32906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 21 Oct 2020 16:14:41 +0300 Subject: drm/i915: Fix potential overflows in ilk ips calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bunch of the ips calculations require 64bit math. In particular 'corr' and 'corr2' look like they can overflow on 32bit systems. Switch to explicit u64 for those. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20201021131443.25616-3-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/gt/intel_rps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/gt/intel_rps.c') diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index e2d7ef5f6dc9..0db565d2be9a 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1281,8 +1281,9 @@ static unsigned long __ips_gfx_val(struct intel_ips *ips) { struct intel_rps *rps = container_of(ips, typeof(*rps), ips); struct intel_uncore *uncore = rps_to_uncore(rps); - unsigned long t, corr, state1, corr2, state2; + unsigned int t, state1, state2; u32 pxvid, ext_v; + u64 corr, corr2; lockdep_assert_held(&mchdev_lock); @@ -1303,11 +1304,10 @@ static unsigned long __ips_gfx_val(struct intel_ips *ips) else /* < 50 */ corr = t * 301 + 1004; - corr = corr * 150142 * state1 / 10000 - 78642; - corr /= 100000; - corr2 = corr * ips->corr; + corr = div_u64(corr * 150142 * state1, 10000) - 78642; + corr2 = div_u64(corr, 100000) * ips->corr; - state2 = corr2 * state1 / 10000; + state2 = div_u64(corr2 * state1, 10000); state2 /= 100; /* convert to mW */ __gen5_ips_update(ips); -- cgit v1.2.3 From c6073d4c923b5ce39ff33a63a07c633036656ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 21 Oct 2020 16:14:43 +0300 Subject: drm/i915: Clean up the irq enable/disable for ilk rps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's unmask the PCU event irq _after_ we've set up the hardware and software to deal with the fallout. We can also drop the PCU event bit from DEIER except when we need it for rps. And on the disable side we replace the hand rolled (and unlocked) DEIER/IIR/IMR frobbing with ilk_disable_display_irq(). Ocd does require me to reorder it to be symmetric with the enable path however. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20201021131443.25616-5-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/gt/intel_rps.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/gt/intel_rps.c') diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 0db565d2be9a..466ec671b379 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -509,6 +509,7 @@ static unsigned int init_emon(struct intel_uncore *uncore) static bool gen5_rps_enable(struct intel_rps *rps) { + struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); u8 fstart, vstart; u32 rgvmodectl; @@ -566,6 +567,10 @@ static bool gen5_rps_enable(struct intel_rps *rps) rps->ips.last_count2 = intel_uncore_read(uncore, GFXEC); rps->ips.last_time2 = ktime_get_raw_ns(); + spin_lock(&i915->irq_lock); + ilk_enable_display_irq(i915, DE_PCU_EVENT); + spin_unlock(&i915->irq_lock); + spin_unlock_irq(&mchdev_lock); rps->ips.corr = init_emon(uncore); @@ -575,11 +580,16 @@ static bool gen5_rps_enable(struct intel_rps *rps) static void gen5_rps_disable(struct intel_rps *rps) { + struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); u16 rgvswctl; spin_lock_irq(&mchdev_lock); + spin_lock(&i915->irq_lock); + ilk_disable_display_irq(i915, DE_PCU_EVENT); + spin_unlock(&i915->irq_lock); + rgvswctl = intel_uncore_read16(uncore, MEMSWCTL); /* Ack interrupts, disable EFC interrupt */ @@ -587,11 +597,6 @@ static void gen5_rps_disable(struct intel_rps *rps) intel_uncore_read(uncore, MEMINTREN) & ~MEMINT_EVAL_CHG_EN); intel_uncore_write(uncore, MEMINTRSTS, MEMINT_EVAL_CHG); - intel_uncore_write(uncore, DEIER, - intel_uncore_read(uncore, DEIER) & ~DE_PCU_EVENT); - intel_uncore_write(uncore, DEIIR, DE_PCU_EVENT); - intel_uncore_write(uncore, DEIMR, - intel_uncore_read(uncore, DEIMR) | DE_PCU_EVENT); /* Go back to the starting frequency */ gen5_rps_set(rps, rps->idle_freq); -- cgit v1.2.3