Commit 9c878557 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915/gt: Use the RPM config register to determine clk frequencies



For many configuration details within RC6 and RPS we are programming
intervals for the internal clocks. From gen11, these clocks are
configuration via the RPM_CONFIG and so for convenience, we would like
to convert to/from more natural units (ns).

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Andi Shyti <andi.shyti@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: default avatarAndi Shyti <andi.shyti@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200424162805.25920-2-chris@chris-wilson.co.uk
parent 555a3224
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ gt-y += \
	gt/intel_ggtt.o \
	gt/intel_ggtt_fencing.o \
	gt/intel_gt.o \
	gt/intel_gt_clock_utils.o \
	gt/intel_gt_irq.o \
	gt/intel_gt_pm.o \
	gt/intel_gt_pm_irq.o \
+39 −18
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include "debugfs_gt_pm.h"
#include "i915_drv.h"
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"
#include "intel_llc.h"
#include "intel_rc6.h"
#include "intel_rps.h"
@@ -300,8 +301,9 @@ static int frequency_show(struct seq_file *m, void *unused)
		u32 rp_state_cap;
		u32 rpmodectl, rpinclimit, rpdeclimit;
		u32 rpstat, cagf, reqf;
		u32 rpupei, rpcurup, rpprevup;
		u32 rpdownei, rpcurdown, rpprevdown;
		u32 rpcurupei, rpcurup, rpprevup;
		u32 rpcurdownei, rpcurdown, rpprevdown;
		u32 rpupei, rpupt, rpdownei, rpdownt;
		u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask;
		int max_freq;

@@ -337,9 +339,16 @@ static int frequency_show(struct seq_file *m, void *unused)
		rpupei = intel_uncore_read(uncore, GEN6_RP_CUR_UP_EI) & GEN6_CURICONT_MASK;
		rpcurup = intel_uncore_read(uncore, GEN6_RP_CUR_UP) & GEN6_CURBSYTAVG_MASK;
		rpprevup = intel_uncore_read(uncore, GEN6_RP_PREV_UP) & GEN6_CURBSYTAVG_MASK;
		rpdownei = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK;
		rpcurdownei = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK;
		rpcurdown = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK;
		rpprevdown = intel_uncore_read(uncore, GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK;

		rpupei = intel_uncore_read(uncore, GEN6_RP_UP_EI);
		rpupt = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD);

		rpdownei = intel_uncore_read(uncore, GEN6_RP_DOWN_EI);
		rpdownt = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD);

		cagf = intel_rps_read_actual_frequency(rps);

		intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
@@ -394,23 +403,35 @@ static int frequency_show(struct seq_file *m, void *unused)
		seq_printf(m, "RPDECLIMIT: 0x%08x\n", rpdeclimit);
		seq_printf(m, "RPNSWREQ: %dMHz\n", reqf);
		seq_printf(m, "CAGF: %dMHz\n", cagf);
		seq_printf(m, "RP CUR UP EI: %d (%dus)\n",
			   rpupei, GT_PM_INTERVAL_TO_US(i915, rpupei));
		seq_printf(m, "RP CUR UP: %d (%dus)\n",
			   rpcurup, GT_PM_INTERVAL_TO_US(i915, rpcurup));
		seq_printf(m, "RP PREV UP: %d (%dus)\n",
			   rpprevup, GT_PM_INTERVAL_TO_US(i915, rpprevup));
		seq_printf(m, "RP CUR UP EI: %d (%dns)\n",
			   rpcurupei,
			   intel_gt_pm_interval_to_ns(gt, rpcurupei));
		seq_printf(m, "RP CUR UP: %d (%dns)\n",
			   rpcurup, intel_gt_pm_interval_to_ns(gt, rpcurup));
		seq_printf(m, "RP PREV UP: %d (%dns)\n",
			   rpprevup, intel_gt_pm_interval_to_ns(gt, rpprevup));
		seq_printf(m, "Up threshold: %d%%\n",
			   rps->power.up_threshold);

		seq_printf(m, "RP CUR DOWN EI: %d (%dus)\n",
			   rpdownei, GT_PM_INTERVAL_TO_US(i915, rpdownei));
		seq_printf(m, "RP CUR DOWN: %d (%dus)\n",
			   rpcurdown, GT_PM_INTERVAL_TO_US(i915, rpcurdown));
		seq_printf(m, "RP PREV DOWN: %d (%dus)\n",
			   rpprevdown, GT_PM_INTERVAL_TO_US(i915, rpprevdown));
		seq_printf(m, "RP UP EI: %d (%dns)\n",
			   rpupei, intel_gt_pm_interval_to_ns(gt, rpupei));
		seq_printf(m, "RP UP THRESHOLD: %d (%dns)\n",
			   rpupt, intel_gt_pm_interval_to_ns(gt, rpupt));

		seq_printf(m, "RP CUR DOWN EI: %d (%dns)\n",
			   rpcurdownei,
			   intel_gt_pm_interval_to_ns(gt, rpcurdownei));
		seq_printf(m, "RP CUR DOWN: %d (%dns)\n",
			   rpcurdown,
			   intel_gt_pm_interval_to_ns(gt, rpcurdown));
		seq_printf(m, "RP PREV DOWN: %d (%dns)\n",
			   rpprevdown,
			   intel_gt_pm_interval_to_ns(gt, rpprevdown));
		seq_printf(m, "Down threshold: %d%%\n",
			   rps->power.down_threshold);
		seq_printf(m, "RP DOWN EI: %d (%dns)\n",
			   rpdownei, intel_gt_pm_interval_to_ns(gt, rpdownei));
		seq_printf(m, "RP DOWN THRESHOLD: %d (%dns)\n",
			   rpdownt, intel_gt_pm_interval_to_ns(gt, rpdownt));

		max_freq = (IS_GEN9_LP(i915) ? rp_state_cap >> 0 :
			    rp_state_cap >> 16) & 0xff;
+3 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include "i915_drv.h"
#include "intel_context.h"
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"
#include "intel_gt_pm.h"
#include "intel_gt_requests.h"
#include "intel_mocs.h"
@@ -576,6 +577,8 @@ int intel_gt_init(struct intel_gt *gt)
	 */
	intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);

	intel_gt_init_clock_frequency(gt);

	err = intel_gt_init_scratch(gt, IS_GEN(gt->i915, 2) ? SZ_256K : SZ_4K);
	if (err)
		goto out_fw;
+102 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2020 Intel Corporation
 */

#include "i915_drv.h"
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"

#define MHZ_19_2 19200000 /* 19.2MHz, 52.083ns */
#define MHZ_24 24000000 /* 24MHz, 83.333ns */
#define MHZ_25 25000000 /* 25MHz, 80ns */

static u32 read_clock_frequency(const struct intel_gt *gt)
{
	if (INTEL_GEN(gt->i915) >= 11) {
		u32 config;

		config = intel_uncore_read(gt->uncore, RPM_CONFIG0);
		config &= GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK;
		config >>= GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT;

		switch (config) {
		case 0: return MHZ_24;
		case 1:
		case 2: return MHZ_19_2;
		default:
		case 3: return MHZ_25;
		}
	} else if (INTEL_GEN(gt->i915) >= 9) {
		if (IS_GEN9_LP(gt->i915))
			return MHZ_19_2;
		else
			return MHZ_24;
	} else {
		return MHZ_25;
	}
}

void intel_gt_init_clock_frequency(struct intel_gt *gt)
{
	/*
	 * Note that on gen11+, the clock frequency may be reconfigured.
	 * We do not, and we assume nobody else does.
	 */
	gt->clock_frequency = read_clock_frequency(gt);
	GT_TRACE(gt,
		 "Using clock frequency: %dkHz\n",
		 gt->clock_frequency / 1000);
}

#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
void intel_gt_check_clock_frequency(const struct intel_gt *gt)
{
	if (gt->clock_frequency != read_clock_frequency(gt)) {
		dev_err(gt->i915->drm.dev,
			"GT clock frequency changed, was %uHz, now %uHz!\n",
			gt->clock_frequency,
			read_clock_frequency(gt));
	}
}
#endif

static u64 div_u64_roundup(u64 nom, u32 den)
{
	return div_u64(nom + den - 1, den);
}

u32 intel_gt_clock_interval_to_ns(const struct intel_gt *gt, u32 count)
{
	return div_u64_roundup(mul_u32_u32(count, 1000 * 1000 * 1000),
			       gt->clock_frequency);
}

u32 intel_gt_pm_interval_to_ns(const struct intel_gt *gt, u32 count)
{
	return intel_gt_clock_interval_to_ns(gt, 16 * count);
}

u32 intel_gt_ns_to_clock_interval(const struct intel_gt *gt, u32 ns)
{
	return div_u64_roundup(mul_u32_u32(gt->clock_frequency, ns),
			       1000 * 1000 * 1000);
}

u32 intel_gt_ns_to_pm_interval(const struct intel_gt *gt, u32 ns)
{
	u32 val;

	/*
	 * Make these a multiple of magic 25 to avoid SNB (eg. Dell XPS
	 * 8300) freezing up around GPU hangs. Looks as if even
	 * scheduling/timer interrupts start misbehaving if the RPS
	 * EI/thresholds are "bad", leading to a very sluggish or even
	 * frozen machine.
	 */
	val = DIV_ROUND_UP(intel_gt_ns_to_clock_interval(gt, ns), 16);
	if (IS_GEN(gt->i915, 6))
		val = roundup(val, 25);

	return val;
}
+27 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT */
/*
 * Copyright © 2020 Intel Corporation
 */

#ifndef __INTEL_GT_CLOCK_UTILS_H__
#define __INTEL_GT_CLOCK_UTILS_H__

#include <linux/types.h>

struct intel_gt;

void intel_gt_init_clock_frequency(struct intel_gt *gt);

#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
void intel_gt_check_clock_frequency(const struct intel_gt *gt);
#else
static inline void intel_gt_check_clock_frequency(const struct intel_gt *gt) {}
#endif

u32 intel_gt_clock_interval_to_ns(const struct intel_gt *gt, u32 count);
u32 intel_gt_pm_interval_to_ns(const struct intel_gt *gt, u32 count);

u32 intel_gt_ns_to_clock_interval(const struct intel_gt *gt, u32 ns);
u32 intel_gt_ns_to_pm_interval(const struct intel_gt *gt, u32 ns);

#endif /* __INTEL_GT_CLOCK_UTILS_H__ */
Loading