We can compute system time corresponding to GPU timestamp by taking a reference point and then adding delta time computed using timecounter and cyclecounter support in kernel. We have to configure cyclecounter with the GPU timestamp frequency. In further patches we can leverage timecounter_cyc2time function to compute the system time corresponding to GPU timestamp cycles derived from OA report. Important thing to note is timecounter_cyc2time considers time backwards if delta timestamp is more than half the max ns time covered by counter. (It will be ~35min for 36 bit counter. If this much sampling duration is needed we will have to update tc->nsec by explicitly reading the timecounter after duration less than 35min during sampling) On enabling perf stream we start the timecounter/cyclecounter and while collecting OA samples we translate GPU timestamp to System timestamp. Earlier approach that was based on cross-timestamp is not needed. It was being used to approximate the frequency based on invalid assumptions (possibly drift was being seen in the time due to precision issue). The precision of time from GPU clocks is already in ns and timecounter takes care of it as verified over variable durations. Cross-timestamp might be valuable to get the precise reference point w.r.t device and system time but it needs a support for reading ART counter from i915 which I find not available for i915. Hence, we are compensating the offset to setup the reference point ourselves. With this approach we have very fine precision of device and system time only differing by 5-10us. Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@xxxxxxxxx> Cc: Lionel Landwerlin <lionel.g.landwerlin@xxxxxxxxx> Cc: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Cc: Sourab Gupta <sourab.gupta@xxxxxxxxx> Cc: Matthew Auld <matthew.auld@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 9 +++++++ drivers/gpu/drm/i915/i915_perf.c | 53 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 6 +++++ 3 files changed, 68 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2158a75..e08bc85 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -43,6 +43,7 @@ #include <linux/pm_qos.h> #include <linux/reservation.h> #include <linux/shmem_fs.h> +#include <linux/timecounter.h> #include <drm/drmP.h> #include <drm/intel-gtt.h> @@ -2149,6 +2150,14 @@ struct i915_perf_stream { * @oa_config: The OA configuration used by the stream. */ struct i915_oa_config *oa_config; + + /** + * System time correlation variables. + */ + struct cyclecounter cc; + spinlock_t systime_lock; + struct timespec64 start_systime; + struct timecounter tc; }; /** diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 00be015..72ddc34 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -192,6 +192,7 @@ */ #include <linux/anon_inodes.h> +#include <linux/clocksource.h> #include <linux/sizes.h> #include <linux/uuid.h> @@ -2391,6 +2392,56 @@ static unsigned int i915_perf_poll(struct file *file, poll_table *wait) } /** + * i915_cyclecounter_read - read raw cycle/timestamp counter + * @cc: cyclecounter structure + */ +static u64 i915_cyclecounter_read(const struct cyclecounter *cc) +{ + struct i915_perf_stream *stream = container_of(cc, typeof(*stream), cc); + struct drm_i915_private *dev_priv = stream->dev_priv; + u64 ts_count; + + intel_runtime_pm_get(dev_priv); + ts_count = I915_READ64_2x32(GEN4_TIMESTAMP, + GEN7_TIMESTAMP_UDW); + intel_runtime_pm_put(dev_priv); + + return ts_count; +} + +static void i915_perf_init_cyclecounter(struct i915_perf_stream *stream) +{ + struct drm_i915_private *dev_priv = stream->dev_priv; + int cs_ts_freq = dev_priv->perf.oa.timestamp_frequency; + struct cyclecounter *cc = &stream->cc; + u32 maxsec; + + cc->read = i915_cyclecounter_read; + cc->mask = CYCLECOUNTER_MASK(CS_TIMESTAMP_WIDTH(dev_priv)); + maxsec = cc->mask / cs_ts_freq; + + clocks_calc_mult_shift(&cc->mult, &cc->shift, cs_ts_freq, + NSEC_PER_SEC, maxsec); +} + +static void i915_perf_init_timecounter(struct i915_perf_stream *stream) +{ +#define SYSTIME_START_OFFSET 350000 /* Counter read takes about 350us */ + unsigned long flags; + u64 ns; + + i915_perf_init_cyclecounter(stream); + spin_lock_init(&stream->systime_lock); + + getnstimeofday64(&stream->start_systime); + ns = timespec64_to_ns(&stream->start_systime) + SYSTIME_START_OFFSET; + + spin_lock_irqsave(&stream->systime_lock, flags); + timecounter_init(&stream->tc, &stream->cc, ns); + spin_unlock_irqrestore(&stream->systime_lock, flags); +} + +/** * i915_perf_enable_locked - handle `I915_PERF_IOCTL_ENABLE` ioctl * @stream: A disabled i915 perf stream * @@ -2408,6 +2459,8 @@ static void i915_perf_enable_locked(struct i915_perf_stream *stream) /* Allow stream->ops->enable() to refer to this */ stream->enabled = true; + i915_perf_init_timecounter(stream); + if (stream->ops->enable) stream->ops->enable(stream); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cfdf4f8..e7e6966 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8882,6 +8882,12 @@ enum skl_power_gate { /* Gen4+ Timestamp and Pipe Frame time stamp registers */ #define GEN4_TIMESTAMP _MMIO(0x2358) +#define GEN7_TIMESTAMP_UDW _MMIO(0x235C) +#define PRE_GEN7_TIMESTAMP_WIDTH 32 +#define GEN7_TIMESTAMP_WIDTH 36 +#define CS_TIMESTAMP_WIDTH(dev_priv) \ + (INTEL_GEN(dev_priv) < 7 ? PRE_GEN7_TIMESTAMP_WIDTH : \ + GEN7_TIMESTAMP_WIDTH) #define ILK_TIMESTAMP_HI _MMIO(0x70070) #define IVB_TIMESTAMP_CTR _MMIO(0x44070) -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx