mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 03:10:30 -04:00
Merge tag 'drm-intel-gt-next-2024-12-18' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next
Driver Changes: - More accurate engine busyness metrics with GuC submission (Umesh) - Ensure partial BO segment offset never exceeds allowed max (Krzysztof) - Flush GuC CT receive tasklet during reset preparation (Zhanjun) - Code cleanups and refactoring (David, Lucas) - Debugging improvements (Jesus) - Selftest improvements (Sk) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/Z2KadNXgumx1aQMP@jlahtine-mobl.ger.corp.intel.com
This commit is contained in:
@@ -126,9 +126,6 @@ execlists_active(const struct intel_engine_execlists *execlists)
|
||||
return active;
|
||||
}
|
||||
|
||||
struct i915_request *
|
||||
execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists);
|
||||
|
||||
static inline u32
|
||||
intel_read_status_page(const struct intel_engine_cs *engine, int reg)
|
||||
{
|
||||
|
||||
@@ -343,6 +343,11 @@ struct intel_engine_guc_stats {
|
||||
* @start_gt_clk: GT clock time of last idle to active transition.
|
||||
*/
|
||||
u64 start_gt_clk;
|
||||
|
||||
/**
|
||||
* @total: The last value of total returned
|
||||
*/
|
||||
u64 total;
|
||||
};
|
||||
|
||||
union intel_engine_tlb_inv_reg {
|
||||
|
||||
@@ -405,15 +405,6 @@ __unwind_incomplete_requests(struct intel_engine_cs *engine)
|
||||
return active;
|
||||
}
|
||||
|
||||
struct i915_request *
|
||||
execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists)
|
||||
{
|
||||
struct intel_engine_cs *engine =
|
||||
container_of(execlists, typeof(*engine), execlists);
|
||||
|
||||
return __unwind_incomplete_requests(engine);
|
||||
}
|
||||
|
||||
static void
|
||||
execlists_context_status_change(struct i915_request *rq, unsigned long status)
|
||||
{
|
||||
|
||||
@@ -1125,6 +1125,7 @@ static u64 measure_power(struct intel_rps *rps, int *freq)
|
||||
static u64 measure_power_at(struct intel_rps *rps, int *freq)
|
||||
{
|
||||
*freq = rps_set_check(rps, *freq);
|
||||
msleep(100);
|
||||
return measure_power(rps, freq);
|
||||
}
|
||||
|
||||
|
||||
@@ -1243,6 +1243,21 @@ static void __get_engine_usage_record(struct intel_engine_cs *engine,
|
||||
} while (++i < 6);
|
||||
}
|
||||
|
||||
static void __set_engine_usage_record(struct intel_engine_cs *engine,
|
||||
u32 last_in, u32 id, u32 total)
|
||||
{
|
||||
struct iosys_map rec_map = intel_guc_engine_usage_record_map(engine);
|
||||
|
||||
#define record_write(map_, field_, val_) \
|
||||
iosys_map_wr_field(map_, 0, struct guc_engine_usage_record, field_, val_)
|
||||
|
||||
record_write(&rec_map, last_switch_in_stamp, last_in);
|
||||
record_write(&rec_map, current_context_index, id);
|
||||
record_write(&rec_map, total_runtime, total);
|
||||
|
||||
#undef record_write
|
||||
}
|
||||
|
||||
static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct intel_engine_guc_stats *stats = &engine->stats.guc;
|
||||
@@ -1363,9 +1378,12 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now)
|
||||
total += intel_gt_clock_interval_to_ns(gt, clk);
|
||||
}
|
||||
|
||||
if (total > stats->total)
|
||||
stats->total = total;
|
||||
|
||||
spin_unlock_irqrestore(&guc->timestamp.lock, flags);
|
||||
|
||||
return ns_to_ktime(total);
|
||||
return ns_to_ktime(stats->total);
|
||||
}
|
||||
|
||||
static void guc_enable_busyness_worker(struct intel_guc *guc)
|
||||
@@ -1431,8 +1449,21 @@ static void __reset_guc_busyness_stats(struct intel_guc *guc)
|
||||
|
||||
guc_update_pm_timestamp(guc, &unused);
|
||||
for_each_engine(engine, gt, id) {
|
||||
struct intel_engine_guc_stats *stats = &engine->stats.guc;
|
||||
|
||||
guc_update_engine_gt_clks(engine);
|
||||
engine->stats.guc.prev_total = 0;
|
||||
|
||||
/*
|
||||
* If resetting a running context, accumulate the active
|
||||
* time as well since there will be no context switch.
|
||||
*/
|
||||
if (stats->running) {
|
||||
u64 clk = guc->timestamp.gt_stamp - stats->start_gt_clk;
|
||||
|
||||
stats->total_gt_clks += clk;
|
||||
}
|
||||
stats->prev_total = 0;
|
||||
stats->running = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&guc->timestamp.lock, flags);
|
||||
@@ -1543,6 +1574,9 @@ static void guc_timestamp_ping(struct work_struct *wrk)
|
||||
|
||||
static int guc_action_enable_usage_stats(struct intel_guc *guc)
|
||||
{
|
||||
struct intel_gt *gt = guc_to_gt(guc);
|
||||
struct intel_engine_cs *engine;
|
||||
enum intel_engine_id id;
|
||||
u32 offset = intel_guc_engine_usage_offset(guc);
|
||||
u32 action[] = {
|
||||
INTEL_GUC_ACTION_SET_ENG_UTIL_BUFF,
|
||||
@@ -1550,6 +1584,9 @@ static int guc_action_enable_usage_stats(struct intel_guc *guc)
|
||||
0,
|
||||
};
|
||||
|
||||
for_each_engine(engine, gt, id)
|
||||
__set_engine_usage_record(engine, 0, 0xffffffff, 0);
|
||||
|
||||
return intel_guc_send(guc, action, ARRAY_SIZE(action));
|
||||
}
|
||||
|
||||
@@ -1688,6 +1725,10 @@ void intel_guc_submission_reset_prepare(struct intel_guc *guc)
|
||||
spin_lock_irq(guc_to_gt(guc)->irq_lock);
|
||||
spin_unlock_irq(guc_to_gt(guc)->irq_lock);
|
||||
|
||||
/* Flush tasklet */
|
||||
tasklet_disable(&guc->ct.receive_tasklet);
|
||||
tasklet_enable(&guc->ct.receive_tasklet);
|
||||
|
||||
guc_flush_submissions(guc);
|
||||
guc_flush_destroyed_contexts(guc);
|
||||
flush_work(&guc->ct.requests.worker);
|
||||
@@ -2005,6 +2046,8 @@ void intel_guc_submission_cancel_requests(struct intel_guc *guc)
|
||||
|
||||
void intel_guc_submission_reset_finish(struct intel_guc *guc)
|
||||
{
|
||||
int outstanding;
|
||||
|
||||
/* Reset called during driver load or during wedge? */
|
||||
if (unlikely(!guc_submission_initialized(guc) ||
|
||||
!intel_guc_is_fw_running(guc) ||
|
||||
@@ -2018,8 +2061,10 @@ void intel_guc_submission_reset_finish(struct intel_guc *guc)
|
||||
* see in CI if this happens frequently / a precursor to taking down the
|
||||
* machine.
|
||||
*/
|
||||
if (atomic_read(&guc->outstanding_submission_g2h))
|
||||
guc_err(guc, "Unexpected outstanding GuC to Host in reset finish\n");
|
||||
outstanding = atomic_read(&guc->outstanding_submission_g2h);
|
||||
if (outstanding)
|
||||
guc_err(guc, "Unexpected outstanding GuC to Host response(s) in reset finish: %d\n",
|
||||
outstanding);
|
||||
atomic_set(&guc->outstanding_submission_g2h, 0);
|
||||
|
||||
intel_guc_global_policies_update(guc);
|
||||
|
||||
@@ -143,8 +143,8 @@ int remap_io_sg(struct vm_area_struct *vma,
|
||||
/* We rely on prevalidation of the io-mapping to skip track_pfn(). */
|
||||
GEM_BUG_ON((vma->vm_flags & EXPECTED_FLAGS) != EXPECTED_FLAGS);
|
||||
|
||||
while (offset >= sg_dma_len(r.sgt.sgp) >> PAGE_SHIFT) {
|
||||
offset -= sg_dma_len(r.sgt.sgp) >> PAGE_SHIFT;
|
||||
while (offset >= r.sgt.max >> PAGE_SHIFT) {
|
||||
offset -= r.sgt.max >> PAGE_SHIFT;
|
||||
r.sgt = __sgt_iter(__sg_next(r.sgt.sgp), use_dma(iobase));
|
||||
if (!r.sgt.sgp)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -302,7 +302,7 @@ void i915_pmu_gt_parked(struct intel_gt *gt)
|
||||
{
|
||||
struct i915_pmu *pmu = >->i915->pmu;
|
||||
|
||||
if (!pmu->base.event_init)
|
||||
if (!pmu->registered)
|
||||
return;
|
||||
|
||||
spin_lock_irq(&pmu->lock);
|
||||
@@ -324,7 +324,7 @@ void i915_pmu_gt_unparked(struct intel_gt *gt)
|
||||
{
|
||||
struct i915_pmu *pmu = >->i915->pmu;
|
||||
|
||||
if (!pmu->base.event_init)
|
||||
if (!pmu->registered)
|
||||
return;
|
||||
|
||||
spin_lock_irq(&pmu->lock);
|
||||
@@ -626,7 +626,7 @@ static int i915_pmu_event_init(struct perf_event *event)
|
||||
struct drm_i915_private *i915 = pmu_to_i915(pmu);
|
||||
int ret;
|
||||
|
||||
if (pmu->closed)
|
||||
if (!pmu->registered)
|
||||
return -ENODEV;
|
||||
|
||||
if (event->attr.type != event->pmu->type)
|
||||
@@ -724,7 +724,7 @@ static void i915_pmu_event_read(struct perf_event *event)
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
u64 prev, new;
|
||||
|
||||
if (pmu->closed) {
|
||||
if (!pmu->registered) {
|
||||
event->hw.state = PERF_HES_STOPPED;
|
||||
return;
|
||||
}
|
||||
@@ -850,7 +850,7 @@ static void i915_pmu_event_start(struct perf_event *event, int flags)
|
||||
{
|
||||
struct i915_pmu *pmu = event_to_pmu(event);
|
||||
|
||||
if (pmu->closed)
|
||||
if (!pmu->registered)
|
||||
return;
|
||||
|
||||
i915_pmu_enable(event);
|
||||
@@ -861,7 +861,7 @@ static void i915_pmu_event_stop(struct perf_event *event, int flags)
|
||||
{
|
||||
struct i915_pmu *pmu = event_to_pmu(event);
|
||||
|
||||
if (pmu->closed)
|
||||
if (!pmu->registered)
|
||||
goto out;
|
||||
|
||||
if (flags & PERF_EF_UPDATE)
|
||||
@@ -877,7 +877,7 @@ static int i915_pmu_event_add(struct perf_event *event, int flags)
|
||||
{
|
||||
struct i915_pmu *pmu = event_to_pmu(event);
|
||||
|
||||
if (pmu->closed)
|
||||
if (!pmu->registered)
|
||||
return -ENODEV;
|
||||
|
||||
if (flags & PERF_EF_START)
|
||||
@@ -1177,8 +1177,6 @@ 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);
|
||||
|
||||
GEM_BUG_ON(!pmu->base.event_init);
|
||||
|
||||
/* Select the first online CPU as a designated reader. */
|
||||
if (cpumask_empty(&i915_pmu_cpumask))
|
||||
cpumask_set_cpu(cpu, &i915_pmu_cpumask);
|
||||
@@ -1191,13 +1189,11 @@ 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;
|
||||
|
||||
GEM_BUG_ON(!pmu->base.event_init);
|
||||
|
||||
/*
|
||||
* Unregistering an instance generates a CPU offline event which we must
|
||||
* ignore to avoid incorrectly modifying the shared i915_pmu_cpumask.
|
||||
*/
|
||||
if (pmu->closed)
|
||||
if (!pmu->registered)
|
||||
return 0;
|
||||
|
||||
if (cpumask_test_and_clear_cpu(cpu, &i915_pmu_cpumask)) {
|
||||
@@ -1218,7 +1214,7 @@ static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum cpuhp_state cpuhp_slot = CPUHP_INVALID;
|
||||
static enum cpuhp_state cpuhp_state = CPUHP_INVALID;
|
||||
|
||||
int i915_pmu_init(void)
|
||||
{
|
||||
@@ -1232,28 +1228,28 @@ int i915_pmu_init(void)
|
||||
pr_notice("Failed to setup cpuhp state for i915 PMU! (%d)\n",
|
||||
ret);
|
||||
else
|
||||
cpuhp_slot = ret;
|
||||
cpuhp_state = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i915_pmu_exit(void)
|
||||
{
|
||||
if (cpuhp_slot != CPUHP_INVALID)
|
||||
cpuhp_remove_multi_state(cpuhp_slot);
|
||||
if (cpuhp_state != CPUHP_INVALID)
|
||||
cpuhp_remove_multi_state(cpuhp_state);
|
||||
}
|
||||
|
||||
static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
|
||||
{
|
||||
if (cpuhp_slot == CPUHP_INVALID)
|
||||
if (cpuhp_state == CPUHP_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
return cpuhp_state_add_instance(cpuhp_slot, &pmu->cpuhp.node);
|
||||
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_slot, &pmu->cpuhp.node);
|
||||
cpuhp_state_remove_instance(cpuhp_state, &pmu->cpuhp.node);
|
||||
}
|
||||
|
||||
void i915_pmu_register(struct drm_i915_private *i915)
|
||||
@@ -1265,7 +1261,6 @@ void i915_pmu_register(struct drm_i915_private *i915)
|
||||
&i915_pmu_cpumask_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
spin_lock_init(&pmu->lock);
|
||||
@@ -1316,6 +1311,8 @@ void i915_pmu_register(struct drm_i915_private *i915)
|
||||
if (ret)
|
||||
goto err_unreg;
|
||||
|
||||
pmu->registered = true;
|
||||
|
||||
return;
|
||||
|
||||
err_unreg:
|
||||
@@ -1323,7 +1320,6 @@ void i915_pmu_register(struct drm_i915_private *i915)
|
||||
err_groups:
|
||||
kfree(pmu->base.attr_groups);
|
||||
err_attr:
|
||||
pmu->base.event_init = NULL;
|
||||
free_event_attributes(pmu);
|
||||
err_name:
|
||||
if (IS_DGFX(i915))
|
||||
@@ -1336,23 +1332,17 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
|
||||
{
|
||||
struct i915_pmu *pmu = &i915->pmu;
|
||||
|
||||
if (!pmu->base.event_init)
|
||||
if (!pmu->registered)
|
||||
return;
|
||||
|
||||
/*
|
||||
* "Disconnect" the PMU callbacks - since all are atomic synchronize_rcu
|
||||
* ensures all currently executing ones will have exited before we
|
||||
* proceed with unregistration.
|
||||
*/
|
||||
pmu->closed = true;
|
||||
synchronize_rcu();
|
||||
/* Disconnect the PMU callbacks */
|
||||
pmu->registered = false;
|
||||
|
||||
hrtimer_cancel(&pmu->timer);
|
||||
|
||||
i915_pmu_unregister_cpuhp_state(pmu);
|
||||
|
||||
perf_pmu_unregister(&pmu->base);
|
||||
pmu->base.event_init = NULL;
|
||||
kfree(pmu->base.attr_groups);
|
||||
if (IS_DGFX(i915))
|
||||
kfree(pmu->name);
|
||||
|
||||
@@ -68,9 +68,9 @@ struct i915_pmu {
|
||||
*/
|
||||
struct pmu base;
|
||||
/**
|
||||
* @closed: i915 is unregistering.
|
||||
* @registered: PMU is registered and not in the unregistering process.
|
||||
*/
|
||||
bool closed;
|
||||
bool registered;
|
||||
/**
|
||||
* @name: Name as registered with perf core.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user