mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
Merge tag 'drm-intel-gt-next-2025-02-26' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next
UAPI Changes: - Add sysfs for SLPC power profiles [slpc] (Vinay Belgaumkar) Driver Changes: Fixes/improvements/new stuff: - Fix zero delta busyness issue [pmu] (Umesh Nerlige Ramappa) - Fix page cleanup on DMA remap failure (Brian Geffon) - Debug print LRC state entries only if the context is pinned [guc] (Daniele Ceraolo Spurio) - Drop custom hotplug code [pmu] (Lucas De Marchi) - Use spin_lock_irqsave() in interruptible context [guc] (Krzysztof Karas) - Add wait on depth stall done bit handling [gen12] (Juha-Pekka Heikkila) Miscellaneous: - Change throttle criteria for rps [selftest] (Raag Jadav) - Add debug print about hw config table size (John Harrison) - Include requested frequency in slow firmware load messages [uc] (John Harrison) - Remove i915_pmu_event_event_idx() [pmu] (Lucas De Marchi) - Remove unused live_context_for_engine (Dr. David Alan Gilbert) - Add Wa_22010465259 in its respective WA list (Ranu Maurya) - Correct frequency handling in RPS power measurement [selftests] (Sk Anirban) - Add helper function slpc_measure_power [guc/slpc] (Sk Anirban) - Revert "drm/i915/gt: Log reason for setting TAINT_WARN at reset" [gt] (Sebastian Brzezinka) - Avoid using uninitialized context [selftests] (Krzysztof Karas) - Use struct_size() helper in kmalloc() (luoqing) - Use prandom in selftest [selftests] (Markus Theil) - Replace kmap with its safer kmap_local_page counterpart [gt] (Andi Shyti) Merges: - Merge drm/drm-next into drm-intel-gt-next (Tvrtko Ursulin) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Tvrtko Ursulin <tursulin@igalia.com> Link: https://patchwork.freedesktop.org/patch/msgid/Z77NLt2mR7SqxJ4u@linux
This commit is contained in:
@@ -107,44 +107,6 @@ err_ctx:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
struct i915_gem_context *
|
||||
live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
|
||||
{
|
||||
struct i915_gem_engines *engines;
|
||||
struct i915_gem_context *ctx;
|
||||
struct intel_sseu null_sseu = {};
|
||||
struct intel_context *ce;
|
||||
|
||||
engines = alloc_engines(1);
|
||||
if (!engines)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ctx = live_context(engine->i915, file);
|
||||
if (IS_ERR(ctx)) {
|
||||
__free_engines(engines, 0);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ce = intel_context_create(engine);
|
||||
if (IS_ERR(ce)) {
|
||||
__free_engines(engines, 0);
|
||||
return ERR_CAST(ce);
|
||||
}
|
||||
|
||||
intel_context_set_gem(ce, ctx, null_sseu);
|
||||
engines->engines[0] = ce;
|
||||
engines->num_engines = 1;
|
||||
|
||||
mutex_lock(&ctx->engines_mutex);
|
||||
i915_gem_context_set_user_engines(ctx);
|
||||
engines = rcu_replace_pointer(ctx->engines, engines, 1);
|
||||
mutex_unlock(&ctx->engines_mutex);
|
||||
|
||||
engines_idle_release(ctx, engines);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct i915_gem_context *
|
||||
kernel_context(struct drm_i915_private *i915,
|
||||
struct i915_address_space *vm)
|
||||
|
||||
@@ -23,9 +23,6 @@ void mock_context_close(struct i915_gem_context *ctx);
|
||||
struct i915_gem_context *
|
||||
live_context(struct drm_i915_private *i915, struct file *file);
|
||||
|
||||
struct i915_gem_context *
|
||||
live_context_for_engine(struct intel_engine_cs *engine, struct file *file);
|
||||
|
||||
struct i915_gem_context *kernel_context(struct drm_i915_private *i915,
|
||||
struct i915_address_space *vm);
|
||||
void kernel_context_close(struct i915_gem_context *ctx);
|
||||
|
||||
@@ -103,8 +103,7 @@ static struct dma_buf *mock_dmabuf(int npages)
|
||||
struct dma_buf *dmabuf;
|
||||
int i;
|
||||
|
||||
mock = kmalloc(sizeof(*mock) + npages * sizeof(struct page *),
|
||||
GFP_KERNEL);
|
||||
mock = kmalloc(struct_size(mock, pages, npages), GFP_KERNEL);
|
||||
if (!mock)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
||||
@@ -750,7 +750,7 @@ static void swizzle_page(struct page *page)
|
||||
char *vaddr;
|
||||
int i;
|
||||
|
||||
vaddr = kmap(page);
|
||||
vaddr = kmap_local_page(page);
|
||||
|
||||
for (i = 0; i < PAGE_SIZE; i += 128) {
|
||||
memcpy(temp, &vaddr[i], 64);
|
||||
@@ -758,7 +758,7 @@ static void swizzle_page(struct page *page)
|
||||
memcpy(&vaddr[i + 64], temp, 64);
|
||||
}
|
||||
|
||||
kunmap(page);
|
||||
kunmap_local(vaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -409,6 +409,9 @@
|
||||
#define GEN7_SO_PRIM_STORAGE_NEEDED(n) _MMIO(0x5240 + (n) * 8)
|
||||
#define GEN7_SO_PRIM_STORAGE_NEEDED_UDW(n) _MMIO(0x5240 + (n) * 8 + 4)
|
||||
|
||||
#define GEN8_WM_CHICKEN2 MCR_REG(0x5584)
|
||||
#define WAIT_ON_DEPTH_STALL_DONE_DISABLE REG_BIT(5)
|
||||
|
||||
#define GEN9_WM_CHICKEN3 _MMIO(0x5588)
|
||||
#define GEN9_FACTOR_IN_CLR_VAL_HIZ (1 << 9)
|
||||
|
||||
|
||||
@@ -464,6 +464,45 @@ static ssize_t slpc_ignore_eff_freq_store(struct kobject *kobj,
|
||||
return err ?: count;
|
||||
}
|
||||
|
||||
static ssize_t slpc_power_profile_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
struct intel_guc_slpc *slpc = >->uc.guc.slpc;
|
||||
|
||||
switch (slpc->power_profile) {
|
||||
case SLPC_POWER_PROFILES_BASE:
|
||||
return sysfs_emit(buff, "[%s] %s\n", "base", "power_saving");
|
||||
case SLPC_POWER_PROFILES_POWER_SAVING:
|
||||
return sysfs_emit(buff, "%s [%s]\n", "base", "power_saving");
|
||||
}
|
||||
|
||||
return sysfs_emit(buff, "%u\n", slpc->power_profile);
|
||||
}
|
||||
|
||||
static ssize_t slpc_power_profile_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buff, size_t count)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
struct intel_guc_slpc *slpc = >->uc.guc.slpc;
|
||||
char power_saving[] = "power_saving";
|
||||
char base[] = "base";
|
||||
int err;
|
||||
u32 val;
|
||||
|
||||
if (!strncmp(buff, power_saving, sizeof(power_saving) - 1))
|
||||
val = SLPC_POWER_PROFILES_POWER_SAVING;
|
||||
else if (!strncmp(buff, base, sizeof(base) - 1))
|
||||
val = SLPC_POWER_PROFILES_BASE;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
err = intel_guc_slpc_set_power_profile(slpc, val);
|
||||
return err ?: count;
|
||||
}
|
||||
|
||||
struct intel_gt_bool_throttle_attr {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
@@ -668,6 +707,7 @@ INTEL_GT_ATTR_RO(media_RP0_freq_mhz);
|
||||
INTEL_GT_ATTR_RO(media_RPn_freq_mhz);
|
||||
|
||||
INTEL_GT_ATTR_RW(slpc_ignore_eff_freq);
|
||||
INTEL_GT_ATTR_RW(slpc_power_profile);
|
||||
|
||||
static const struct attribute *media_perf_power_attrs[] = {
|
||||
&attr_media_freq_factor.attr,
|
||||
@@ -864,6 +904,13 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
|
||||
gt_warn(gt, "failed to create ignore_eff_freq sysfs (%pe)", ERR_PTR(ret));
|
||||
}
|
||||
|
||||
if (intel_uc_uses_guc_slpc(>->uc)) {
|
||||
ret = sysfs_create_file(kobj, &attr_slpc_power_profile.attr);
|
||||
if (ret)
|
||||
gt_warn(gt, "failed to create slpc_power_profile sysfs (%pe)",
|
||||
ERR_PTR(ret));
|
||||
}
|
||||
|
||||
if (i915_mmio_reg_valid(intel_gt_perf_limit_reasons_reg(gt))) {
|
||||
ret = sysfs_create_files(kobj, throttle_reason_attrs);
|
||||
if (ret)
|
||||
|
||||
@@ -1113,7 +1113,6 @@ static bool __intel_gt_unset_wedged(struct intel_gt *gt)
|
||||
* Warn CI about the unrecoverable wedged condition.
|
||||
* Time for a reboot.
|
||||
*/
|
||||
gt_err(gt, "Unrecoverable wedged condition\n");
|
||||
add_taint_for_CI(gt->i915, TAINT_WARN);
|
||||
return false;
|
||||
}
|
||||
@@ -1272,10 +1271,8 @@ void intel_gt_reset(struct intel_gt *gt,
|
||||
}
|
||||
|
||||
ret = resume(gt);
|
||||
if (ret) {
|
||||
gt_err(gt, "Failed to resume (%d)\n", ret);
|
||||
if (ret)
|
||||
goto taint;
|
||||
}
|
||||
|
||||
finish:
|
||||
reset_finish(gt, awake);
|
||||
@@ -1641,7 +1638,6 @@ void intel_gt_set_wedged_on_init(struct intel_gt *gt)
|
||||
set_bit(I915_WEDGED_ON_INIT, >->reset.flags);
|
||||
|
||||
/* Wedged on init is non-recoverable */
|
||||
gt_err(gt, "Non-recoverable wedged on init\n");
|
||||
add_taint_for_CI(gt->i915, TAINT_WARN);
|
||||
}
|
||||
|
||||
|
||||
@@ -1025,6 +1025,10 @@ void intel_rps_boost(struct i915_request *rq)
|
||||
if (rps_uses_slpc(rps)) {
|
||||
slpc = rps_to_slpc(rps);
|
||||
|
||||
/* Waitboost should not be done with power saving profile */
|
||||
if (slpc->power_profile == SLPC_POWER_PROFILES_POWER_SAVING)
|
||||
return;
|
||||
|
||||
if (slpc->min_freq_softlimit >= slpc->boost_freq)
|
||||
return;
|
||||
|
||||
|
||||
@@ -691,16 +691,17 @@ static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine,
|
||||
struct drm_i915_private *i915 = engine->i915;
|
||||
|
||||
/*
|
||||
* Wa_1409142259:tgl,dg1,adl-p
|
||||
* Wa_1409142259:tgl,dg1,adl-p,adl-n
|
||||
* Wa_1409347922:tgl,dg1,adl-p
|
||||
* Wa_1409252684:tgl,dg1,adl-p
|
||||
* Wa_1409217633:tgl,dg1,adl-p
|
||||
* Wa_1409207793:tgl,dg1,adl-p
|
||||
* Wa_1409178076:tgl,dg1,adl-p
|
||||
* Wa_1408979724:tgl,dg1,adl-p
|
||||
* Wa_14010443199:tgl,rkl,dg1,adl-p
|
||||
* Wa_14010698770:tgl,rkl,dg1,adl-s,adl-p
|
||||
* Wa_1409342910:tgl,rkl,dg1,adl-s,adl-p
|
||||
* Wa_1409178076:tgl,dg1,adl-p,adl-n
|
||||
* Wa_1408979724:tgl,dg1,adl-p,adl-n
|
||||
* Wa_14010443199:tgl,rkl,dg1,adl-p,adl-n
|
||||
* Wa_14010698770:tgl,rkl,dg1,adl-s,adl-p,adl-n
|
||||
* Wa_1409342910:tgl,rkl,dg1,adl-s,adl-p,adl-n
|
||||
* Wa_22010465259:tgl,rkl,dg1,adl-s,adl-p,adl-n
|
||||
*/
|
||||
wa_masked_en(wal, GEN11_COMMON_SLICE_CHICKEN3,
|
||||
GEN12_DISABLE_CPS_AWARE_COLOR_PIPE);
|
||||
@@ -741,6 +742,12 @@ static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine,
|
||||
/* Wa_1606376872 */
|
||||
wa_masked_en(wal, COMMON_SLICE_CHICKEN4, DISABLE_TDC_LOAD_BALANCING_CALC);
|
||||
}
|
||||
|
||||
/*
|
||||
* This bit must be set to enable performance optimization for fast
|
||||
* clears.
|
||||
*/
|
||||
wa_mcr_write_or(wal, GEN8_WM_CHICKEN2, WAIT_ON_DEPTH_STALL_DONE_DISABLE);
|
||||
}
|
||||
|
||||
static void dg1_ctx_workarounds_init(struct intel_engine_cs *engine,
|
||||
|
||||
@@ -477,12 +477,13 @@ int live_rps_control(void *arg)
|
||||
limit, intel_gpu_freq(rps, limit),
|
||||
min, max, ktime_to_ns(min_dt), ktime_to_ns(max_dt));
|
||||
|
||||
if (limit == rps->min_freq) {
|
||||
pr_err("%s: GPU throttled to minimum!\n",
|
||||
engine->name);
|
||||
if (limit != rps->max_freq) {
|
||||
u32 throttle = intel_uncore_read(gt->uncore,
|
||||
intel_gt_perf_limit_reasons_reg(gt));
|
||||
|
||||
pr_warn("%s: GPU throttled with reasons 0x%08x\n",
|
||||
engine->name, throttle & GT0_PERF_LIMIT_REASONS_MASK);
|
||||
show_pstate_limits(rps);
|
||||
err = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
if (igt_flush_test(gt->i915)) {
|
||||
@@ -1115,7 +1116,7 @@ static u64 measure_power(struct intel_rps *rps, int *freq)
|
||||
for (i = 0; i < 5; i++)
|
||||
x[i] = __measure_power(5);
|
||||
|
||||
*freq = (*freq + intel_rps_read_actual_frequency(rps)) / 2;
|
||||
*freq = (*freq + read_cagf(rps)) / 2;
|
||||
|
||||
/* A simple triangle filter for better result stability */
|
||||
sort(x, 5, sizeof(*x), cmp_u64, NULL);
|
||||
|
||||
@@ -95,6 +95,21 @@ static int slpc_restore_freq(struct intel_guc_slpc *slpc, u32 min, u32 max)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 slpc_measure_power(struct intel_rps *rps, int *freq)
|
||||
{
|
||||
u64 x[5];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
x[i] = __measure_power(5);
|
||||
|
||||
*freq = (*freq + intel_rps_read_actual_frequency(rps)) / 2;
|
||||
|
||||
/* A simple triangle filter for better result stability */
|
||||
sort(x, 5, sizeof(*x), cmp_u64, NULL);
|
||||
return div_u64(x[1] + 2 * x[2] + x[3], 4);
|
||||
}
|
||||
|
||||
static u64 measure_power_at_freq(struct intel_gt *gt, int *freq, u64 *power)
|
||||
{
|
||||
int err = 0;
|
||||
@@ -103,7 +118,7 @@ static u64 measure_power_at_freq(struct intel_gt *gt, int *freq, u64 *power)
|
||||
if (err)
|
||||
return err;
|
||||
*freq = intel_rps_read_actual_frequency(>->rps);
|
||||
*power = measure_power(>->rps, freq);
|
||||
*power = slpc_measure_power(>->rps, freq);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ static int __shmem_rw(struct file *file, loff_t off,
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
|
||||
vaddr = kmap(page);
|
||||
vaddr = kmap_local_page(page);
|
||||
if (write) {
|
||||
memcpy(vaddr + offset_in_page(off), ptr, this);
|
||||
set_page_dirty(page);
|
||||
@@ -116,7 +116,7 @@ static int __shmem_rw(struct file *file, loff_t off,
|
||||
memcpy(ptr, vaddr + offset_in_page(off), this);
|
||||
}
|
||||
mark_page_accessed(page);
|
||||
kunmap(page);
|
||||
kunmap_local(vaddr);
|
||||
put_page(page);
|
||||
|
||||
len -= this;
|
||||
@@ -143,11 +143,11 @@ int shmem_read_to_iosys_map(struct file *file, loff_t off,
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
|
||||
vaddr = kmap(page);
|
||||
vaddr = kmap_local_page(page);
|
||||
iosys_map_memcpy_to(map, map_off, vaddr + offset_in_page(off),
|
||||
this);
|
||||
mark_page_accessed(page);
|
||||
kunmap(page);
|
||||
kunmap_local(vaddr);
|
||||
put_page(page);
|
||||
|
||||
len -= this;
|
||||
|
||||
@@ -228,6 +228,11 @@ struct slpc_optimized_strategies {
|
||||
|
||||
#define SLPC_OPTIMIZED_STRATEGY_COMPUTE REG_BIT(0)
|
||||
|
||||
enum slpc_power_profiles {
|
||||
SLPC_POWER_PROFILES_BASE = 0x0,
|
||||
SLPC_POWER_PROFILES_POWER_SAVING = 0x1
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: SLPC H2G MESSAGE FORMAT
|
||||
*
|
||||
|
||||
@@ -259,13 +259,14 @@ static int guc_wait_ucode(struct intel_guc *guc)
|
||||
} else if (delta_ms > 200) {
|
||||
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(>->rps), before_freq,
|
||||
guc_warn(guc, "excessive init time: [freq = %dMHz -> %dMHz vs %dMHz, perf_limit_reasons = 0x%08X]\n",
|
||||
before_freq, intel_rps_read_actual_frequency(>->rps),
|
||||
intel_rps_get_requested_frequency(>->rps),
|
||||
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(>->rps),
|
||||
before_freq, status, count, ret);
|
||||
guc_dbg(guc, "init took %lldms, freq = %dMHz -> %dMHz vs %dMHz, status = 0x%08X, count = %d, ret = %d\n",
|
||||
delta_ms, before_freq, intel_rps_read_actual_frequency(>->rps),
|
||||
intel_rps_get_requested_frequency(>->rps), status, count, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "gt/intel_hwconfig.h"
|
||||
#include "i915_drv.h"
|
||||
#include "i915_memcpy.h"
|
||||
#include "intel_guc_print.h"
|
||||
|
||||
/*
|
||||
* GuC has a blob containing hardware configuration information (HWConfig).
|
||||
@@ -42,6 +43,8 @@ static int __guc_action_get_hwconfig(struct intel_guc *guc,
|
||||
};
|
||||
int ret;
|
||||
|
||||
guc_dbg(guc, "Querying HW config table: size = %d, offset = 0x%08X\n",
|
||||
ggtt_size, ggtt_offset);
|
||||
ret = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0);
|
||||
if (ret == -ENXIO)
|
||||
return -ENOENT;
|
||||
|
||||
@@ -15,6 +15,34 @@
|
||||
#include "gt/intel_gt_regs.h"
|
||||
#include "gt/intel_rps.h"
|
||||
|
||||
/**
|
||||
* DOC: SLPC - Dynamic Frequency management
|
||||
*
|
||||
* Single Loop Power Control (SLPC) is a GuC algorithm that manages
|
||||
* GT frequency based on busyness and how KMD initializes it. SLPC is
|
||||
* almost completely in control after initialization except for a few
|
||||
* scenarios mentioned below.
|
||||
*
|
||||
* KMD uses the concept of waitboost to ramp frequency to RP0 when there
|
||||
* are pending submissions for a context. It achieves this by sending GuC a
|
||||
* request to update the min frequency to RP0. Waitboost is disabled
|
||||
* when the request retires.
|
||||
*
|
||||
* Another form of frequency control happens through per-context hints.
|
||||
* A context can be marked as low latency during creation. That will ensure
|
||||
* that SLPC uses an aggressive frequency ramp when that context is active.
|
||||
*
|
||||
* Power profiles add another level of control to these mechanisms.
|
||||
* When power saving profile is chosen, SLPC will use conservative
|
||||
* thresholds to ramp frequency, thus saving power. KMD will disable
|
||||
* waitboosts as well, which achieves further power savings. Base profile
|
||||
* is default and ensures balanced performance for any workload.
|
||||
*
|
||||
* Lastly, users have some level of control through sysfs, where min/max
|
||||
* frequency values can be altered and the use of efficient freq
|
||||
* can be toggled.
|
||||
*/
|
||||
|
||||
static inline struct intel_guc *slpc_to_guc(struct intel_guc_slpc *slpc)
|
||||
{
|
||||
return container_of(slpc, struct intel_guc, slpc);
|
||||
@@ -265,6 +293,8 @@ int intel_guc_slpc_init(struct intel_guc_slpc *slpc)
|
||||
slpc->num_boosts = 0;
|
||||
slpc->media_ratio_mode = SLPC_MEDIA_RATIO_MODE_DYNAMIC_CONTROL;
|
||||
|
||||
slpc->power_profile = SLPC_POWER_PROFILES_BASE;
|
||||
|
||||
mutex_init(&slpc->lock);
|
||||
INIT_WORK(&slpc->boost_work, slpc_boost_work);
|
||||
|
||||
@@ -575,6 +605,34 @@ int intel_guc_slpc_set_media_ratio_mode(struct intel_guc_slpc *slpc, u32 val)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int intel_guc_slpc_set_power_profile(struct intel_guc_slpc *slpc, u32 val)
|
||||
{
|
||||
struct drm_i915_private *i915 = slpc_to_i915(slpc);
|
||||
intel_wakeref_t wakeref;
|
||||
int ret = 0;
|
||||
|
||||
if (val > SLPC_POWER_PROFILES_POWER_SAVING)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&slpc->lock);
|
||||
wakeref = intel_runtime_pm_get(&i915->runtime_pm);
|
||||
|
||||
ret = slpc_set_param(slpc,
|
||||
SLPC_PARAM_POWER_PROFILE,
|
||||
val);
|
||||
if (ret)
|
||||
guc_err(slpc_to_guc(slpc),
|
||||
"Failed to set power profile to %d: %pe\n",
|
||||
val, ERR_PTR(ret));
|
||||
else
|
||||
slpc->power_profile = val;
|
||||
|
||||
intel_runtime_pm_put(&i915->runtime_pm, wakeref);
|
||||
mutex_unlock(&slpc->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void intel_guc_pm_intrmsk_enable(struct intel_gt *gt)
|
||||
{
|
||||
u32 pm_intrmsk_mbz = 0;
|
||||
@@ -736,6 +794,13 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
|
||||
/* Enable SLPC Optimized Strategy for compute */
|
||||
intel_guc_slpc_set_strategy(slpc, SLPC_OPTIMIZED_STRATEGY_COMPUTE);
|
||||
|
||||
/* Set cached value of power_profile */
|
||||
ret = intel_guc_slpc_set_power_profile(slpc, slpc->power_profile);
|
||||
if (unlikely(ret)) {
|
||||
guc_probe_error(guc, "Failed to set SLPC power profile: %pe\n", ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,5 +46,6 @@ void intel_guc_slpc_boost(struct intel_guc_slpc *slpc);
|
||||
void intel_guc_slpc_dec_waiters(struct intel_guc_slpc *slpc);
|
||||
int intel_guc_slpc_set_ignore_eff_freq(struct intel_guc_slpc *slpc, bool val);
|
||||
int intel_guc_slpc_set_strategy(struct intel_guc_slpc *slpc, u32 val);
|
||||
int intel_guc_slpc_set_power_profile(struct intel_guc_slpc *slpc, u32 val);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,9 @@ struct intel_guc_slpc {
|
||||
u32 max_freq_softlimit;
|
||||
bool ignore_eff_freq;
|
||||
|
||||
/* Base or power saving */
|
||||
u32 power_profile;
|
||||
|
||||
/* cached media ratio mode */
|
||||
u32 media_ratio_mode;
|
||||
|
||||
|
||||
@@ -489,13 +489,15 @@ int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
|
||||
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(>->rps), before_freq,
|
||||
huc_warn(huc, "excessive auth time: [freq = %dMHz -> %dMHz vs %dMHz, perf_limit_reasons = 0x%08X]\n",
|
||||
before_freq, intel_rps_read_actual_frequency(>->rps),
|
||||
intel_rps_get_requested_frequency(>->rps),
|
||||
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(>->rps),
|
||||
before_freq, huc->status[type].reg.reg, count, ret);
|
||||
huc_dbg(huc, "auth took %lldms, freq = %dMHz -> %dMHz vs %dMHz, status = 0x%08X, count = %d, ret = %d\n",
|
||||
delta_ms, before_freq, intel_rps_read_actual_frequency(>->rps),
|
||||
intel_rps_get_requested_frequency(>->rps),
|
||||
huc->status[type].reg.reg, count, ret);
|
||||
}
|
||||
|
||||
/* mark the load process as complete even if the wait failed */
|
||||
|
||||
@@ -71,8 +71,6 @@ static const struct {
|
||||
{ .init = i915_vma_resource_module_init,
|
||||
.exit = i915_vma_resource_module_exit },
|
||||
{ .init = i915_mock_selftests },
|
||||
{ .init = i915_pmu_init,
|
||||
.exit = i915_pmu_exit },
|
||||
{ .init = i915_pci_register_driver,
|
||||
.exit = i915_pci_unregister_driver },
|
||||
{ .init = i915_perf_sysctl_register,
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
BIT(I915_SAMPLE_WAIT) | \
|
||||
BIT(I915_SAMPLE_SEMA))
|
||||
|
||||
static cpumask_t i915_pmu_cpumask;
|
||||
static unsigned int i915_pmu_target_cpu = -1;
|
||||
|
||||
static struct i915_pmu *event_to_pmu(struct perf_event *event)
|
||||
{
|
||||
return container_of(event->pmu, struct i915_pmu, base);
|
||||
@@ -642,10 +639,6 @@ static int i915_pmu_event_init(struct perf_event *event)
|
||||
if (event->cpu < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* only allow running on one cpu at a time */
|
||||
if (!cpumask_test_cpu(event->cpu, &i915_pmu_cpumask))
|
||||
return -EINVAL;
|
||||
|
||||
if (is_engine_event(event))
|
||||
ret = engine_event_init(event);
|
||||
else
|
||||
@@ -891,11 +884,6 @@ static void i915_pmu_event_del(struct perf_event *event, int flags)
|
||||
i915_pmu_event_stop(event, PERF_EF_UPDATE);
|
||||
}
|
||||
|
||||
static int i915_pmu_event_event_idx(struct perf_event *event)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct i915_str_attribute {
|
||||
struct device_attribute attr;
|
||||
const char *str;
|
||||
@@ -940,23 +928,6 @@ static ssize_t i915_pmu_event_show(struct device *dev,
|
||||
return sprintf(buf, "config=0x%lx\n", eattr->val);
|
||||
}
|
||||
|
||||
static ssize_t cpumask_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return cpumap_print_to_pagebuf(true, buf, &i915_pmu_cpumask);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(cpumask);
|
||||
|
||||
static struct attribute *i915_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group i915_pmu_cpumask_attr_group = {
|
||||
.attrs = i915_cpumask_attrs,
|
||||
};
|
||||
|
||||
#define __event(__counter, __name, __unit) \
|
||||
{ \
|
||||
.counter = (__counter), \
|
||||
@@ -1173,92 +1144,12 @@ static void free_event_attributes(struct i915_pmu *pmu)
|
||||
pmu->pmu_attr = NULL;
|
||||
}
|
||||
|
||||
static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node);
|
||||
|
||||
/* Select the first online CPU as a designated reader. */
|
||||
if (cpumask_empty(&i915_pmu_cpumask))
|
||||
cpumask_set_cpu(cpu, &i915_pmu_cpumask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node);
|
||||
unsigned int target = i915_pmu_target_cpu;
|
||||
|
||||
/*
|
||||
* Unregistering an instance generates a CPU offline event which we must
|
||||
* ignore to avoid incorrectly modifying the shared i915_pmu_cpumask.
|
||||
*/
|
||||
if (!pmu->registered)
|
||||
return 0;
|
||||
|
||||
if (cpumask_test_and_clear_cpu(cpu, &i915_pmu_cpumask)) {
|
||||
target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
|
||||
|
||||
/* Migrate events if there is a valid target */
|
||||
if (target < nr_cpu_ids) {
|
||||
cpumask_set_cpu(target, &i915_pmu_cpumask);
|
||||
i915_pmu_target_cpu = target;
|
||||
}
|
||||
}
|
||||
|
||||
if (target < nr_cpu_ids && target != pmu->cpuhp.cpu) {
|
||||
perf_pmu_migrate_context(&pmu->base, cpu, target);
|
||||
pmu->cpuhp.cpu = target;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum cpuhp_state cpuhp_state = CPUHP_INVALID;
|
||||
|
||||
int i915_pmu_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
|
||||
"perf/x86/intel/i915:online",
|
||||
i915_pmu_cpu_online,
|
||||
i915_pmu_cpu_offline);
|
||||
if (ret < 0)
|
||||
pr_notice("Failed to setup cpuhp state for i915 PMU! (%d)\n",
|
||||
ret);
|
||||
else
|
||||
cpuhp_state = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i915_pmu_exit(void)
|
||||
{
|
||||
if (cpuhp_state != CPUHP_INVALID)
|
||||
cpuhp_remove_multi_state(cpuhp_state);
|
||||
}
|
||||
|
||||
static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
|
||||
{
|
||||
if (cpuhp_state == CPUHP_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
return cpuhp_state_add_instance(cpuhp_state, &pmu->cpuhp.node);
|
||||
}
|
||||
|
||||
static void i915_pmu_unregister_cpuhp_state(struct i915_pmu *pmu)
|
||||
{
|
||||
cpuhp_state_remove_instance(cpuhp_state, &pmu->cpuhp.node);
|
||||
}
|
||||
|
||||
void i915_pmu_register(struct drm_i915_private *i915)
|
||||
{
|
||||
struct i915_pmu *pmu = &i915->pmu;
|
||||
const struct attribute_group *attr_groups[] = {
|
||||
&i915_pmu_format_attr_group,
|
||||
&pmu->events_attr_group,
|
||||
&i915_pmu_cpumask_attr_group,
|
||||
NULL
|
||||
};
|
||||
int ret = -ENOMEM;
|
||||
@@ -1266,7 +1157,6 @@ void i915_pmu_register(struct drm_i915_private *i915)
|
||||
spin_lock_init(&pmu->lock);
|
||||
hrtimer_init(&pmu->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
pmu->timer.function = i915_sample;
|
||||
pmu->cpuhp.cpu = -1;
|
||||
init_rc6(pmu);
|
||||
|
||||
if (IS_DGFX(i915)) {
|
||||
@@ -1295,28 +1185,22 @@ void i915_pmu_register(struct drm_i915_private *i915)
|
||||
|
||||
pmu->base.module = THIS_MODULE;
|
||||
pmu->base.task_ctx_nr = perf_invalid_context;
|
||||
pmu->base.scope = PERF_PMU_SCOPE_SYS_WIDE;
|
||||
pmu->base.event_init = i915_pmu_event_init;
|
||||
pmu->base.add = i915_pmu_event_add;
|
||||
pmu->base.del = i915_pmu_event_del;
|
||||
pmu->base.start = i915_pmu_event_start;
|
||||
pmu->base.stop = i915_pmu_event_stop;
|
||||
pmu->base.read = i915_pmu_event_read;
|
||||
pmu->base.event_idx = i915_pmu_event_event_idx;
|
||||
|
||||
ret = perf_pmu_register(&pmu->base, pmu->name, -1);
|
||||
if (ret)
|
||||
goto err_groups;
|
||||
|
||||
ret = i915_pmu_register_cpuhp_state(pmu);
|
||||
if (ret)
|
||||
goto err_unreg;
|
||||
|
||||
pmu->registered = true;
|
||||
|
||||
return;
|
||||
|
||||
err_unreg:
|
||||
perf_pmu_unregister(&pmu->base);
|
||||
err_groups:
|
||||
kfree(pmu->base.attr_groups);
|
||||
err_attr:
|
||||
@@ -1340,8 +1224,6 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
|
||||
|
||||
hrtimer_cancel(&pmu->timer);
|
||||
|
||||
i915_pmu_unregister_cpuhp_state(pmu);
|
||||
|
||||
perf_pmu_unregister(&pmu->base);
|
||||
kfree(pmu->base.attr_groups);
|
||||
if (IS_DGFX(i915))
|
||||
|
||||
@@ -56,13 +56,6 @@ struct i915_pmu_sample {
|
||||
};
|
||||
|
||||
struct i915_pmu {
|
||||
/**
|
||||
* @cpuhp: Struct used for CPU hotplug handling.
|
||||
*/
|
||||
struct {
|
||||
struct hlist_node node;
|
||||
unsigned int cpu;
|
||||
} cpuhp;
|
||||
/**
|
||||
* @base: PMU base.
|
||||
*/
|
||||
@@ -155,15 +148,11 @@ struct i915_pmu {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
int i915_pmu_init(void);
|
||||
void i915_pmu_exit(void);
|
||||
void i915_pmu_register(struct drm_i915_private *i915);
|
||||
void i915_pmu_unregister(struct drm_i915_private *i915);
|
||||
void i915_pmu_gt_parked(struct intel_gt *gt);
|
||||
void i915_pmu_gt_unparked(struct intel_gt *gt);
|
||||
#else
|
||||
static inline int i915_pmu_init(void) { return 0; }
|
||||
static inline void i915_pmu_exit(void) {}
|
||||
static inline void i915_pmu_register(struct drm_i915_private *i915) {}
|
||||
static inline void i915_pmu_unregister(struct drm_i915_private *i915) {}
|
||||
static inline void i915_pmu_gt_parked(struct intel_gt *gt) {}
|
||||
|
||||
@@ -45,13 +45,15 @@ static void trash_stolen(struct drm_i915_private *i915)
|
||||
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
|
||||
const u64 slot = ggtt->error_capture.start;
|
||||
const resource_size_t size = resource_size(&i915->dsm.stolen);
|
||||
struct rnd_state prng;
|
||||
unsigned long page;
|
||||
u32 prng = 0x12345678;
|
||||
|
||||
/* XXX: fsck. needs some more thought... */
|
||||
if (!i915_ggtt_has_aperture(ggtt))
|
||||
return;
|
||||
|
||||
prandom_seed_state(&prng, 0x12345678);
|
||||
|
||||
for (page = 0; page < size; page += PAGE_SIZE) {
|
||||
const dma_addr_t dma = i915->dsm.stolen.start + page;
|
||||
u32 __iomem *s;
|
||||
@@ -64,8 +66,7 @@ static void trash_stolen(struct drm_i915_private *i915)
|
||||
|
||||
s = io_mapping_map_atomic_wc(&ggtt->iomap, slot);
|
||||
for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) {
|
||||
prng = next_pseudo_random32(prng);
|
||||
iowrite32(prng, &s[x]);
|
||||
iowrite32(prandom_u32_state(&prng), &s[x]);
|
||||
}
|
||||
io_mapping_unmap_atomic(s);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user