Skip to content

Commit

Permalink
drm/i915/gt: Use the RPM config register to determine clk frequencies
Browse files Browse the repository at this point in the history
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: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Andi Shyti <andi.shyti@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: Andi Shyti <andi.shyti@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200424162805.25920-2-chris@chris-wilson.co.uk
  • Loading branch information
Chris Wilson committed Apr 24, 2020
1 parent 555a322 commit 9c87855
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 75 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
57 changes: 39 additions & 18 deletions drivers/gpu/drm/i915/gt/debugfs_gt_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -268,7 +269,7 @@ static int frequency_show(struct seq_file *m, void *unused)
yesno(rpmodectl & GEN6_RP_ENABLE));
seq_printf(m, "SW control enabled: %s\n",
yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) ==
GEN6_RP_MEDIA_SW_MODE));
GEN6_RP_MEDIA_SW_MODE));

vlv_punit_get(i915);
freq_sts = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -372,7 +381,7 @@ static int frequency_show(struct seq_file *m, void *unused)
yesno(rpmodectl & GEN6_RP_ENABLE));
seq_printf(m, "SW control enabled: %s\n",
yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) ==
GEN6_RP_MEDIA_SW_MODE));
GEN6_RP_MEDIA_SW_MODE));

seq_printf(m, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n",
pm_ier, pm_imr, pm_mask);
Expand 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;
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_gt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
102 changes: 102 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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 changes: 27 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_gt_clock_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* 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__ */
3 changes: 3 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_gt_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "intel_context.h"
#include "intel_engine_pm.h"
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"
#include "intel_gt_pm.h"
#include "intel_gt_requests.h"
#include "intel_llc.h"
Expand Down Expand Up @@ -138,6 +139,8 @@ static void gt_sanitize(struct intel_gt *gt, bool force)
wakeref = intel_runtime_pm_get(gt->uncore->rpm);
intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);

intel_gt_check_clock_frequency(gt);

/*
* As we have just resumed the machine and woken the device up from
* deep PCI sleep (presumably D3_cold), assume the HW has been reset
Expand Down
9 changes: 5 additions & 4 deletions drivers/gpu/drm/i915/gt/intel_gt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct intel_gt {
struct list_head closed_vma;
spinlock_t closed_lock; /* guards the list of closed_vma */

ktime_t last_init_time;
struct intel_reset reset;

/**
Expand All @@ -72,14 +73,12 @@ struct intel_gt {
*/
intel_wakeref_t awake;

u32 clock_frequency;

struct intel_llc llc;
struct intel_rc6 rc6;
struct intel_rps rps;

ktime_t last_init_time;

struct i915_vma *scratch;

spinlock_t irq_lock;
u32 gt_imr;
u32 pm_ier;
Expand All @@ -97,6 +96,8 @@ struct intel_gt {
* Reserved for exclusive use by the kernel.
*/
struct i915_address_space *vm;

struct i915_vma *scratch;
};

enum intel_gt_scratch_field {
Expand Down
Loading

0 comments on commit 9c87855

Please sign in to comment.