aboutsummaryrefslogtreecommitdiff
path: root/SOURCES/cachy-fixes.patch
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES/cachy-fixes.patch')
-rw-r--r--SOURCES/cachy-fixes.patch573
1 files changed, 573 insertions, 0 deletions
diff --git a/SOURCES/cachy-fixes.patch b/SOURCES/cachy-fixes.patch
new file mode 100644
index 0000000..1c632df
--- /dev/null
+++ b/SOURCES/cachy-fixes.patch
@@ -0,0 +1,573 @@
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 371531b2a3d0..ddc064b4fc32 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -8327,6 +8327,122 @@ static inline uint32_t get_mem_type(struct drm_framebuffer *fb)
+ return abo->tbo.resource ? abo->tbo.resource->mem_type : 0;
+ }
+
++/* TODO remove duplicate */
++static int amdgpu_dm_plane_get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
++ struct dc_cursor_position *position)
++{
++ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
++ int x, y;
++ int xorigin = 0, yorigin = 0;
++
++ if (!crtc || !plane->state->fb)
++ return 0;
++
++ if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
++ (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
++ DRM_ERROR("%s: bad cursor width or height %d x %d\n",
++ __func__,
++ plane->state->crtc_w,
++ plane->state->crtc_h);
++ return -EINVAL;
++ }
++
++ x = plane->state->crtc_x;
++ y = plane->state->crtc_y;
++
++ if (x <= -amdgpu_crtc->max_cursor_width ||
++ y <= -amdgpu_crtc->max_cursor_height)
++ return 0;
++
++ if (x < 0) {
++ xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
++ x = 0;
++ }
++ if (y < 0) {
++ yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
++ y = 0;
++ }
++ position->enable = true;
++ position->translate_by_source = true;
++ position->x = x;
++ position->y = y;
++ position->x_hotspot = xorigin;
++ position->y_hotspot = yorigin;
++
++ return 0;
++}
++
++static void amdgpu_dm_update_cursor(struct drm_plane *plane,
++ struct drm_plane_state *old_plane_state,
++ struct dc_stream_update *update)
++{
++ struct amdgpu_device *adev = drm_to_adev(plane->dev);
++ struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
++ struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
++ struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
++ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
++ uint64_t address = afb ? afb->address : 0;
++ struct dc_cursor_position position = {0};
++ struct dc_cursor_attributes attributes;
++ int ret;
++
++ if (!plane->state->fb && !old_plane_state->fb)
++ return;
++
++ drm_dbg_atomic(plane->dev, "crtc_id=%d with size %d to %d\n",
++ amdgpu_crtc->crtc_id, plane->state->crtc_w,
++ plane->state->crtc_h);
++
++ ret = amdgpu_dm_plane_get_cursor_position(plane, crtc, &position);
++ if (ret)
++ return;
++
++ if (!position.enable) {
++ /* turn off cursor */
++ if (crtc_state && crtc_state->stream) {
++ dc_stream_set_cursor_position(crtc_state->stream,
++ &position);
++ update->cursor_position = &crtc_state->stream->cursor_position;
++ }
++ return;
++ }
++
++ amdgpu_crtc->cursor_width = plane->state->crtc_w;
++ amdgpu_crtc->cursor_height = plane->state->crtc_h;
++
++ memset(&attributes, 0, sizeof(attributes));
++ attributes.address.high_part = upper_32_bits(address);
++ attributes.address.low_part = lower_32_bits(address);
++ attributes.width = plane->state->crtc_w;
++ attributes.height = plane->state->crtc_h;
++ attributes.color_format = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
++ attributes.rotation_angle = 0;
++ attributes.attribute_flags.value = 0;
++
++ /* Enable cursor degamma ROM on DCN3+ for implicit sRGB degamma in DRM
++ * legacy gamma setup.
++ */
++ if (crtc_state->cm_is_degamma_srgb &&
++ adev->dm.dc->caps.color.dpp.gamma_corr)
++ attributes.attribute_flags.bits.ENABLE_CURSOR_DEGAMMA = 1;
++
++ attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
++
++ if (crtc_state->stream) {
++ if (!dc_stream_set_cursor_attributes(crtc_state->stream,
++ &attributes))
++ DRM_ERROR("DC failed to set cursor attributes\n");
++
++ update->cursor_attributes = &crtc_state->stream->cursor_attributes;
++
++ if (!dc_stream_set_cursor_position(crtc_state->stream,
++ &position))
++ DRM_ERROR("DC failed to set cursor position\n");
++
++ update->cursor_position = &crtc_state->stream->cursor_position;
++ }
++}
++
+ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ struct drm_device *dev,
+ struct amdgpu_display_manager *dm,
+@@ -8350,6 +8466,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ bool cursor_update = false;
+ bool pflip_present = false;
+ bool dirty_rects_changed = false;
++ bool updated_planes_and_streams = false;
+ struct {
+ struct dc_surface_update surface_updates[MAX_SURFACES];
+ struct dc_plane_info plane_infos[MAX_SURFACES];
+@@ -8386,8 +8503,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ /* Cursor plane is handled after stream updates */
+ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+ if ((fb && crtc == pcrtc) ||
+- (old_plane_state->fb && old_plane_state->crtc == pcrtc))
++ (old_plane_state->fb && old_plane_state->crtc == pcrtc)) {
+ cursor_update = true;
++ amdgpu_dm_update_cursor(plane, old_plane_state, &bundle->stream_update);
++ }
+
+ continue;
+ }
+@@ -8660,6 +8779,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ acrtc_state->stream,
+ &bundle->stream_update,
+ bundle->surface_updates);
++ updated_planes_and_streams = true;
+
+ /**
+ * Enable or disable the interrupts on the backend.
+@@ -8737,7 +8857,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ * This avoids redundant programming in the case where we're going
+ * to be disabling a single plane - those pipes are being disabled.
+ */
+- if (acrtc_state->active_planes)
++ if (acrtc_state->active_planes && !updated_planes_and_streams)
+ amdgpu_dm_commit_cursors(state);
+
+ cleanup:
+@@ -8925,7 +9045,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
+
+ memset(&position, 0, sizeof(position));
+ mutex_lock(&dm->dc_lock);
+- dc_stream_set_cursor_position(dm_old_crtc_state->stream, &position);
++ dc_stream_program_cursor_position(dm_old_crtc_state->stream, &position);
+ mutex_unlock(&dm->dc_lock);
+ }
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+index 779880c64575..8c8d0d209d7a 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+@@ -1254,7 +1254,7 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane,
+ /* turn off cursor */
+ if (crtc_state && crtc_state->stream) {
+ mutex_lock(&adev->dm.dc_lock);
+- dc_stream_set_cursor_position(crtc_state->stream,
++ dc_stream_program_cursor_position(crtc_state->stream,
+ &position);
+ mutex_unlock(&adev->dm.dc_lock);
+ }
+@@ -1284,11 +1284,11 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane,
+
+ if (crtc_state->stream) {
+ mutex_lock(&adev->dm.dc_lock);
+- if (!dc_stream_set_cursor_attributes(crtc_state->stream,
++ if (!dc_stream_program_cursor_attributes(crtc_state->stream,
+ &attributes))
+ DRM_ERROR("DC failed to set cursor attributes\n");
+
+- if (!dc_stream_set_cursor_position(crtc_state->stream,
++ if (!dc_stream_program_cursor_position(crtc_state->stream,
+ &position))
+ DRM_ERROR("DC failed to set cursor position\n");
+ mutex_unlock(&adev->dm.dc_lock);
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index d68c83e40d4d..575290784c61 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -3188,6 +3188,83 @@ static bool update_planes_and_stream_state(struct dc *dc,
+
+ }
+
++static void program_cursor_attributes(
++ struct dc *dc,
++ struct dc_stream_state *stream)
++{
++ int i;
++ struct resource_context *res_ctx;
++ struct pipe_ctx *pipe_to_program = NULL;
++
++ if (!stream)
++ return;
++
++ res_ctx = &dc->current_state->res_ctx;
++
++ for (i = 0; i < MAX_PIPES; i++) {
++ struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
++
++ if (pipe_ctx->stream != stream)
++ continue;
++
++ if (!pipe_to_program) {
++ pipe_to_program = pipe_ctx;
++ dc->hwss.cursor_lock(dc, pipe_to_program, true);
++ if (pipe_to_program->next_odm_pipe)
++ dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
++ }
++
++ dc->hwss.set_cursor_attribute(pipe_ctx);
++ if (dc->ctx->dmub_srv)
++ dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
++ if (dc->hwss.set_cursor_sdr_white_level)
++ dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
++ }
++
++ if (pipe_to_program) {
++ dc->hwss.cursor_lock(dc, pipe_to_program, false);
++ if (pipe_to_program->next_odm_pipe)
++ dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
++ }
++}
++
++static void program_cursor_position(
++ struct dc *dc,
++ struct dc_stream_state *stream)
++{
++ int i;
++ struct resource_context *res_ctx;
++ struct pipe_ctx *pipe_to_program = NULL;
++
++ if (!stream)
++ return;
++
++ res_ctx = &dc->current_state->res_ctx;
++
++ for (i = 0; i < MAX_PIPES; i++) {
++ struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
++
++ if (pipe_ctx->stream != stream ||
++ (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) ||
++ !pipe_ctx->plane_state ||
++ (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) ||
++ (!pipe_ctx->plane_res.ipp && !pipe_ctx->plane_res.dpp))
++ continue;
++
++ if (!pipe_to_program) {
++ pipe_to_program = pipe_ctx;
++ dc->hwss.cursor_lock(dc, pipe_to_program, true);
++ }
++
++ dc->hwss.set_cursor_position(pipe_ctx);
++ if (dc->ctx->dmub_srv)
++ dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
++ }
++
++ if (pipe_to_program)
++ dc->hwss.cursor_lock(dc, pipe_to_program, false);
++}
++
+ static void commit_planes_do_stream_update(struct dc *dc,
+ struct dc_stream_state *stream,
+ struct dc_stream_update *stream_update,
+@@ -3248,6 +3325,13 @@ static void commit_planes_do_stream_update(struct dc *dc,
+ }
+ }
+
++ if (stream_update->cursor_attributes) {
++ program_cursor_attributes(dc, stream);
++ }
++
++ if (stream_update->cursor_position) {
++ program_cursor_position(dc, stream);
++ }
+
+ /* Full fe update*/
+ if (update_type == UPDATE_TYPE_FAST)
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+index 51a970fcb5d0..5601ee8a8d41 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+@@ -278,7 +278,6 @@ bool dc_stream_set_cursor_attributes(
+ const struct dc_cursor_attributes *attributes)
+ {
+ struct dc *dc;
+- bool reset_idle_optimizations = false;
+
+ if (NULL == stream) {
+ dm_error("DC: dc_stream is NULL!\n");
+@@ -309,20 +308,36 @@ bool dc_stream_set_cursor_attributes(
+
+ stream->cursor_attributes = *attributes;
+
+- dc_z10_restore(dc);
+- /* disable idle optimizations while updating cursor */
+- if (dc->idle_optimizations_allowed) {
+- dc_allow_idle_optimizations(dc, false);
+- reset_idle_optimizations = true;
+- }
++ return true;
++}
+
+- program_cursor_attributes(dc, stream, attributes);
++bool dc_stream_program_cursor_attributes(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_attributes *attributes)
++{
++ struct dc *dc;
++ bool reset_idle_optimizations = false;
+
+- /* re-enable idle optimizations if necessary */
+- if (reset_idle_optimizations)
+- dc_allow_idle_optimizations(dc, true);
++ dc = stream ? stream->ctx->dc : NULL;
+
+- return true;
++ if (dc_stream_set_cursor_attributes(stream, attributes)) {
++ dc_z10_restore(dc);
++ /* disable idle optimizations while updating cursor */
++ if (dc->idle_optimizations_allowed) {
++ dc_allow_idle_optimizations(dc, false);
++ reset_idle_optimizations = true;
++ }
++
++ program_cursor_attributes(dc, stream, attributes);
++
++ /* re-enable idle optimizations if necessary */
++ if (reset_idle_optimizations)
++ dc_allow_idle_optimizations(dc, true);
++
++ return true;
++ }
++
++ return false;
+ }
+
+ static void program_cursor_position(
+@@ -367,9 +382,6 @@ bool dc_stream_set_cursor_position(
+ struct dc_stream_state *stream,
+ const struct dc_cursor_position *position)
+ {
+- struct dc *dc;
+- bool reset_idle_optimizations = false;
+-
+ if (NULL == stream) {
+ dm_error("DC: dc_stream is NULL!\n");
+ return false;
+@@ -380,24 +392,43 @@ bool dc_stream_set_cursor_position(
+ return false;
+ }
+
++ stream->cursor_position = *position;
++
++ return true;
++}
++
++bool dc_stream_program_cursor_position(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_position *position)
++{
++ struct dc *dc;
++ bool reset_idle_optimizations = false;
++ const struct dc_cursor_position *old_position;
++
++ old_position = stream ? &stream->cursor_position : NULL;
+ dc = stream->ctx->dc;
+- dc_z10_restore(dc);
+
+- /* disable idle optimizations if enabling cursor */
+- if (dc->idle_optimizations_allowed && (!stream->cursor_position.enable || dc->debug.exit_idle_opt_for_cursor_updates)
+- && position->enable) {
+- dc_allow_idle_optimizations(dc, false);
+- reset_idle_optimizations = true;
+- }
++ if (dc_stream_set_cursor_position(stream, position)) {
++ dc_z10_restore(dc);
+
+- stream->cursor_position = *position;
++ /* disable idle optimizations if enabling cursor */
++ if (dc->idle_optimizations_allowed &&
++ (!old_position->enable || dc->debug.exit_idle_opt_for_cursor_updates) &&
++ position->enable) {
++ dc_allow_idle_optimizations(dc, false);
++ reset_idle_optimizations = true;
++ }
+
+- program_cursor_position(dc, stream, position);
+- /* re-enable idle optimizations if necessary */
+- if (reset_idle_optimizations)
+- dc_allow_idle_optimizations(dc, true);
+
+- return true;
++ program_cursor_position(dc, stream, position);
++ /* re-enable idle optimizations if necessary */
++ if (reset_idle_optimizations)
++ dc_allow_idle_optimizations(dc, true);
++
++ return true;
++ }
++
++ return false;
+ }
+
+ bool dc_stream_add_writeback(struct dc *dc,
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
+index ee10941caa59..df86668f560f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
+@@ -327,6 +327,9 @@ struct dc_stream_update {
+
+ struct test_pattern *pending_test_pattern;
+ struct dc_crtc_timing_adjust *crtc_timing_adjust;
++
++ struct dc_cursor_attributes *cursor_attributes;
++ struct dc_cursor_position *cursor_position;
+ };
+
+ bool dc_is_stream_unchanged(
+@@ -478,10 +481,17 @@ bool dc_stream_set_cursor_attributes(
+ struct dc_stream_state *stream,
+ const struct dc_cursor_attributes *attributes);
+
++bool dc_stream_program_cursor_attributes(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_attributes *attributes);
++
+ bool dc_stream_set_cursor_position(
+ struct dc_stream_state *stream,
+ const struct dc_cursor_position *position);
+
++bool dc_stream_program_cursor_position(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_position *position);
+
+ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
+ struct dc_stream_state *stream,
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+index 8bc3d01537bb..f91169c80f7f 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+@@ -1042,7 +1042,7 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
+
+ /* Use copied cursor, and it's okay to not switch back */
+ cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part;
+- dc_stream_set_cursor_attributes(stream, &cursor_attr);
++ dc_stream_program_cursor_attributes(stream, &cursor_attr);
+ }
+
+ /* Enable MALL */
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index 1e020620748d..082f87834503 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -4269,6 +4269,13 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb)
+ }
+ }
+
++static void clear_extent_buffer_reading(struct extent_buffer *eb)
++{
++ clear_bit(EXTENT_BUFFER_READING, &eb->bflags);
++ smp_mb__after_atomic();
++ wake_up_bit(&eb->bflags, EXTENT_BUFFER_READING);
++}
++
+ static void end_bbio_meta_read(struct btrfs_bio *bbio)
+ {
+ struct extent_buffer *eb = bbio->private;
+@@ -4277,6 +4284,13 @@ static void end_bbio_meta_read(struct btrfs_bio *bbio)
+ struct folio_iter fi;
+ u32 bio_offset = 0;
+
++ /*
++ * If the extent buffer is marked UPTODATE before the read operation
++ * completes, other calls to read_extent_buffer_pages() will return
++ * early without waiting for the read to finish, causing data races.
++ */
++ WARN_ON(test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags));
++
+ eb->read_mirror = bbio->mirror_num;
+
+ if (uptodate &&
+@@ -4303,9 +4317,7 @@ static void end_bbio_meta_read(struct btrfs_bio *bbio)
+ bio_offset += len;
+ }
+
+- clear_bit(EXTENT_BUFFER_READING, &eb->bflags);
+- smp_mb__after_atomic();
+- wake_up_bit(&eb->bflags, EXTENT_BUFFER_READING);
++ clear_extent_buffer_reading(eb);
+ free_extent_buffer(eb);
+
+ bio_put(&bbio->bio);
+@@ -4339,9 +4351,7 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num,
+ * will now be set, and we shouldn't read it in again.
+ */
+ if (unlikely(test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))) {
+- clear_bit(EXTENT_BUFFER_READING, &eb->bflags);
+- smp_mb__after_atomic();
+- wake_up_bit(&eb->bflags, EXTENT_BUFFER_READING);
++ clear_extent_buffer_reading(eb);
+ return 0;
+ }
+
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index cf12bfa2a78c..2acf8634008d 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -644,14 +644,16 @@ static __always_inline u32 __bpf_prog_run(const struct bpf_prog *prog,
+ cant_migrate();
+ if (static_branch_unlikely(&bpf_stats_enabled_key)) {
+ struct bpf_prog_stats *stats;
+- u64 start = sched_clock();
++ u64 duration, start = sched_clock();
+ unsigned long flags;
+
+ ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
++
++ duration = sched_clock() - start;
+ stats = this_cpu_ptr(prog->stats);
+ flags = u64_stats_update_begin_irqsave(&stats->syncp);
+ u64_stats_inc(&stats->cnt);
+- u64_stats_add(&stats->nsecs, sched_clock() - start);
++ u64_stats_add(&stats->nsecs, duration);
+ u64_stats_update_end_irqrestore(&stats->syncp, flags);
+ } else {
+ ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
+diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
+index db7599c59c78..146de96e99b8 100644
+--- a/kernel/bpf/trampoline.c
++++ b/kernel/bpf/trampoline.c
+@@ -883,12 +883,13 @@ static void notrace update_prog_stats(struct bpf_prog *prog,
+ * Hence check that 'start' is valid.
+ */
+ start > NO_START_TIME) {
++ u64 duration = sched_clock() - start;
+ unsigned long flags;
+
+ stats = this_cpu_ptr(prog->stats);
+ flags = u64_stats_update_begin_irqsave(&stats->syncp);
+ u64_stats_inc(&stats->cnt);
+- u64_stats_add(&stats->nsecs, sched_clock() - start);
++ u64_stats_add(&stats->nsecs, duration);
+ u64_stats_update_end_irqrestore(&stats->syncp, flags);
+ }
+ }
+--
+2.45.2
+