switch (config_counter(config)) { case I915_PMU_ACTUAL_FREQUENCY:
val = __I915_PMU_ACTUAL_FREQUENCY_ENABLED; break; case I915_PMU_REQUESTED_FREQUENCY:
val = __I915_PMU_REQUESTED_FREQUENCY_ENABLED; break; case I915_PMU_RC6_RESIDENCY:
val = __I915_PMU_RC6_RESIDENCY_ENABLED; break; default: /* * Events that do not require sampling, or tracking state * transitions between enabled and disabled can be ignored.
*/ return -1;
}
/* * Only some counters need the sampling timer. * * We start with a bitmask of all currently enabled events.
*/
enable = pmu->enable;
/* * Mask out all the ones which do not need the timer, or in * other words keep all the ones that could need the timer.
*/
enable &= frequency_enabled_mask() | ENGINE_SAMPLE_MASK;
/* * Also there is software busyness tracking available we do not * need the timer for I915_SAMPLE_BUSY counter.
*/ if (i915->caps.scheduler & I915_SCHEDULER_CAP_ENGINE_BUSY_STATS)
enable &= ~BIT(I915_SAMPLE_BUSY);
/* * If some bits remain it means we need the sampling timer running.
*/ return enable;
}
wakeref = intel_gt_pm_get_if_awake(gt); if (wakeref) {
val = __get_rc6(gt);
intel_gt_pm_put_async(gt, wakeref);
}
spin_lock_irqsave(&pmu->lock, flags);
if (wakeref) {
store_sample(pmu, gt_id, __I915_SAMPLE_RC6, val);
} else { /* * We think we are runtime suspended. * * Report the delta from when the device was suspended to now, * on top of the last known real value, as the approximated RC6 * counter value.
*/
val = ktime_since_raw(pmu->sleep_last[gt_id]);
val += read_sample(pmu, gt_id, __I915_SAMPLE_RC6);
}
if (val < read_sample(pmu, gt_id, __I915_SAMPLE_RC6_LAST_REPORTED))
val = read_sample(pmu, gt_id, __I915_SAMPLE_RC6_LAST_REPORTED); else
store_sample(pmu, gt_id, __I915_SAMPLE_RC6_LAST_REPORTED, val);
/* * Signal sampling timer to stop if only engine events are enabled and * GPU went idle.
*/
pmu->unparked &= ~BIT(gt->info.id); if (pmu->unparked == 0)
pmu->timer_enabled = false;
staticbool exclusive_mmio_access(conststruct drm_i915_private *i915)
{ /* * We have to avoid concurrent mmio cache line access on gen7 or * risk a machine hang. For a fun history lesson dig out the old * userspace intel_gpu_top and run it on Ivybridge or Haswell!
*/ return GRAPHICS_VER(i915) == 7;
}
val = ENGINE_READ_FW(engine, RING_CTL); if (val == 0) /* powerwell off => engine idle */ return;
if (val & RING_WAIT)
add_sample(&pmu->sample[I915_SAMPLE_WAIT], period_ns); if (val & RING_WAIT_SEMAPHORE)
add_sample(&pmu->sample[I915_SAMPLE_SEMA], period_ns);
/* No need to sample when busy stats are supported. */ if (intel_engine_supports_stats(engine)) return;
/* * While waiting on a semaphore or event, MI_MODE reports the * ring as idle. However, previously using the seqno, and with * execlists sampling, we account for the ring waiting as the * engine being busy. Therefore, we record the sample as being * busy if either waiting or !idle.
*/
busy = val & (RING_WAIT_SEMAPHORE | RING_WAIT); if (!busy) {
val = ENGINE_READ_FW(engine, RING_MI_MODE);
busy = !(val & MODE_IDLE);
} if (busy)
add_sample(&pmu->sample[I915_SAMPLE_BUSY], period_ns);
}
if (!frequency_sampling_enabled(pmu, gt_id)) return;
/* Report 0/0 (actual/requested) frequency while parked. */
wakeref = intel_gt_pm_get_if_awake(gt); if (!wakeref) return;
if (pmu->enable & config_mask(__I915_PMU_ACTUAL_FREQUENCY(gt_id))) {
u32 val;
/* * We take a quick peek here without using forcewake * so that we don't perturb the system under observation * (forcewake => !rc6 => increased power use). We expect * that if the read fails because it is outside of the * mmio power well, then it will return 0 -- in which * case we assume the system is running at the intended * frequency. Fortunately, the read should rarely fail!
*/
val = intel_rps_read_actual_frequency_fw(rps); if (!val)
val = intel_gpu_freq(rps, rps->cur_freq);
if (!READ_ONCE(pmu->timer_enabled)) return HRTIMER_NORESTART;
now = ktime_get();
period_ns = ktime_to_ns(ktime_sub(now, pmu->timer_last));
pmu->timer_last = now;
/* * Strictly speaking the passed in period may not be 100% accurate for * all internal calculation, since some amount of time can be spent on * grabbing the forcewake. However the potential error from timer call- * back delay greatly dominates this so we keep it simple.
*/
for_each_gt(gt, i915, i) { if (!(pmu->unparked & BIT(i))) continue;
switch (config_counter(config)) { case I915_PMU_ACTUAL_FREQUENCY: if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) /* Requires a mutex for sampling! */ return -ENODEV;
fallthrough; case I915_PMU_REQUESTED_FREQUENCY: if (GRAPHICS_VER(i915) < 6) return -ENODEV; break; case I915_PMU_INTERRUPTS: if (gt_id) return -ENOENT; break; case I915_PMU_RC6_RESIDENCY: if (!gt->rc6.supported) return -ENODEV; break; case I915_PMU_SOFTWARE_GT_AWAKE_TIME: break; default: return -ENOENT;
}
switch (config) { case I915_PMU_ACTUAL_FREQUENCY:
val =
div_u64(read_sample(pmu, gt_id,
__I915_SAMPLE_FREQ_ACT),
USEC_PER_SEC /* to MHz */); break; case I915_PMU_REQUESTED_FREQUENCY:
val =
div_u64(read_sample(pmu, gt_id,
__I915_SAMPLE_FREQ_REQ),
USEC_PER_SEC /* to MHz */); break; case I915_PMU_INTERRUPTS:
val = READ_ONCE(pmu->irq_count); break; case I915_PMU_RC6_RESIDENCY:
val = get_rc6(i915->gt[gt_id]); break; case I915_PMU_SOFTWARE_GT_AWAKE_TIME:
val = ktime_to_ns(intel_gt_get_awake_time(to_gt(i915))); break;
}
}
/* * Start the sampling timer if needed and not already enabled.
*/
__i915_pmu_maybe_start_timer(pmu);
/* * For per-engine events the bitmask and reference counting * is stored per engine.
*/ if (is_engine_event(event)) {
u8 sample = engine_event_sample(event); struct intel_engine_cs *engine;
update: /* * Store the current counter value so we can report the correct delta * for all listeners. Even when the event was already enabled and has * an existing non-zero value.
*/
local64_set(&event->hw.prev_count, __i915_pmu_event_read(event));
}
/* * Decrement the reference count and clear the enabled * bitmask when the last listener on an event goes away.
*/ if (--engine->pmu.enable_count[sample] == 0)
engine->pmu.enable &= ~BIT(sample);
}
GEM_BUG_ON(bit >= ARRAY_SIZE(pmu->enable_count));
GEM_BUG_ON(pmu->enable_count[bit] == 0); /* * Decrement the reference count and clear the enabled * bitmask when the last listener on an event goes away.
*/ if (--pmu->enable_count[bit] == 0) {
pmu->enable &= ~BIT(bit);
pmu->timer_enabled &= pmu_needs_timer(pmu);
}
/* Count how many counters we will be exposing. */
for_each_gt(gt, i915, j) { for (i = 0; i < ARRAY_SIZE(events); i++) {
u64 config = ___I915_PMU_OTHER(j, events[i].counter);
if (!config_status(i915, config))
count++;
}
}
for_each_uabi_engine(engine, i915) { for (i = 0; i < ARRAY_SIZE(engine_events); i++) { if (!engine_event_status(engine,
engine_events[i].sample))
count++;
}
}
/* Allocate attribute objects and table. */
i915_attr = kcalloc(count, sizeof(*i915_attr), GFP_KERNEL); if (!i915_attr) goto err_alloc;
pmu_attr = kcalloc(count, sizeof(*pmu_attr), GFP_KERNEL); if (!pmu_attr) goto err_alloc;
/* Max one pointer of each attribute type plus a termination entry. */
attr = kcalloc(count * 2 + 1, sizeof(*attr), GFP_KERNEL); if (!attr) goto err_alloc;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.