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:
Dave Airlie
2025-03-13 07:54:40 +10:00
23 changed files with 193 additions and 212 deletions

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
/**

View File

@@ -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)

View File

@@ -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 = &gt->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 = &gt->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(&gt->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)

View File

@@ -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, &gt->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);
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);

View File

@@ -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(&gt->rps);
*power = measure_power(&gt->rps, freq);
*power = slpc_measure_power(&gt->rps, freq);
return err;
}

View File

@@ -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;

View File

@@ -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
*

View File

@@ -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(&gt->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(&gt->rps),
intel_rps_get_requested_frequency(&gt->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(&gt->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(&gt->rps),
intel_rps_get_requested_frequency(&gt->rps), status, count, ret);
}
return ret;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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(&gt->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(&gt->rps),
intel_rps_get_requested_frequency(&gt->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(&gt->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(&gt->rps),
intel_rps_get_requested_frequency(&gt->rps),
huc->status[type].reg.reg, count, ret);
}
/* mark the load process as complete even if the wait failed */

View File

@@ -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,

View File

@@ -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))

View File

@@ -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) {}

View File

@@ -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);
}