--- /dev/null
+From 71777f122cab2b0f8829ed04895b872bd32ace09 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Jul 2023 11:11:06 +0100
+Subject: blk-mq: Fix stall due to recursive flush plug
+
+From: Ross Lagerwall <ross.lagerwall@citrix.com>
+
+[ Upstream commit 70904263512a74a3b8941dd9e6e515ca6fc57821 ]
+
+We have seen rare IO stalls as follows:
+
+* blk_mq_plug_issue_direct() is entered with an mq_list containing two
+requests.
+* For the first request, it sets last == false and enters the driver's
+queue_rq callback.
+* The driver queue_rq callback indirectly calls schedule() which calls
+blk_flush_plug(). This may happen if the driver has the
+BLK_MQ_F_BLOCKING flag set and is allowed to sleep in ->queue_rq.
+* blk_flush_plug() handles the remaining request in the mq_list. mq_list
+is now empty.
+* The original call to queue_rq resumes (with last == false).
+* The loop in blk_mq_plug_issue_direct() terminates because there are no
+remaining requests in mq_list.
+
+The IO is now stalled because the last request submitted to the driver
+had last == false and there was no subsequent call to commit_rqs().
+
+Fix this by returning early in blk_mq_flush_plug_list() if rq_count is 0
+which it will be in the recursive case, rather than checking if the
+mq_list is empty. At the same time, adjust one of the callers to skip
+the mq_list empty check as it is not necessary.
+
+Fixes: dc5fc361d891 ("block: attempt direct issue of plug list")
+Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Link: https://lore.kernel.org/r/20230714101106.3635611-1-ross.lagerwall@citrix.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-core.c | 3 +--
+ block/blk-mq.c | 9 ++++++++-
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/block/blk-core.c b/block/blk-core.c
+index 3fc68b9444791..0434f5a8151fe 100644
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -1141,8 +1141,7 @@ void __blk_flush_plug(struct blk_plug *plug, bool from_schedule)
+ {
+ if (!list_empty(&plug->cb_list))
+ flush_plug_callbacks(plug, from_schedule);
+- if (!rq_list_empty(plug->mq_list))
+- blk_mq_flush_plug_list(plug, from_schedule);
++ blk_mq_flush_plug_list(plug, from_schedule);
+ /*
+ * Unconditionally flush out cached requests, even if the unplug
+ * event came from schedule. Since we know hold references to the
+diff --git a/block/blk-mq.c b/block/blk-mq.c
+index 73ed8ccb09ce8..58bf41e8e66c7 100644
+--- a/block/blk-mq.c
++++ b/block/blk-mq.c
+@@ -2754,7 +2754,14 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule)
+ {
+ struct request *rq;
+
+- if (rq_list_empty(plug->mq_list))
++ /*
++ * We may have been called recursively midway through handling
++ * plug->mq_list via a schedule() in the driver's queue_rq() callback.
++ * To avoid mq_list changing under our feet, clear rq_count early and
++ * bail out specifically if rq_count is 0 rather than checking
++ * whether the mq_list is empty.
++ */
++ if (plug->rq_count == 0)
+ return;
+ plug->rq_count = 0;
+
+--
+2.39.2
+
--- /dev/null
+From cb92ac65dcc6547789ae7577b7658551d8bf7d18 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 May 2023 08:04:51 +0200
+Subject: btrfs: factor out a btrfs_verify_page helper
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit ed9ee98ecb4fdbdfe043ee3eec0a65c0745d8669 ]
+
+Split all the conditionals for the fsverity calls in end_page_read into
+a btrfs_verify_page helper to keep the code readable and make additional
+refactoring easier.
+
+Reviewed-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 2c14f0ffdd30 ("btrfs: fix fsverify read error handling in end_page_read")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_io.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index a37a6587efaf0..496c2c9920fc6 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -478,6 +478,15 @@ void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
+ start, end, page_ops, NULL);
+ }
+
++static bool btrfs_verify_page(struct page *page, u64 start)
++{
++ if (!fsverity_active(page->mapping->host) ||
++ PageError(page) || PageUptodate(page) ||
++ start >= i_size_read(page->mapping->host))
++ return true;
++ return fsverity_verify_page(page);
++}
++
+ static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
+ {
+ struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
+@@ -486,11 +495,7 @@ static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
+ start + len <= page_offset(page) + PAGE_SIZE);
+
+ if (uptodate) {
+- if (fsverity_active(page->mapping->host) &&
+- !PageError(page) &&
+- !PageUptodate(page) &&
+- start < i_size_read(page->mapping->host) &&
+- !fsverity_verify_page(page)) {
++ if (!btrfs_verify_page(page, start)) {
+ btrfs_page_set_error(fs_info, page, start, len);
+ } else {
+ btrfs_page_set_uptodate(fs_info, page, start, len);
+--
+2.39.2
+
--- /dev/null
+From 875ef408e105242ca16ec120c132de1c6734ec1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 May 2023 08:04:52 +0200
+Subject: btrfs: fix fsverify read error handling in end_page_read
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit 2c14f0ffdd30bd3d321ad5fe76fcf701746e1df6 ]
+
+Also clear the uptodate bit to make sure the page isn't seen as uptodate
+in the page cache if fsverity verification fails.
+
+Fixes: 146054090b08 ("btrfs: initial fsverity support")
+CC: stable@vger.kernel.org # 5.15+
+Reviewed-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_io.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index 496c2c9920fc6..82b9779deaa88 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -494,12 +494,8 @@ static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
+ ASSERT(page_offset(page) <= start &&
+ start + len <= page_offset(page) + PAGE_SIZE);
+
+- if (uptodate) {
+- if (!btrfs_verify_page(page, start)) {
+- btrfs_page_set_error(fs_info, page, start, len);
+- } else {
+- btrfs_page_set_uptodate(fs_info, page, start, len);
+- }
++ if (uptodate && btrfs_verify_page(page, start)) {
++ btrfs_page_set_uptodate(fs_info, page, start, len);
+ } else {
+ btrfs_page_clear_uptodate(fs_info, page, start, len);
+ btrfs_page_set_error(fs_info, page, start, len);
+--
+2.39.2
+
--- /dev/null
+From bba37123142550a2467252249f109608aae2ce94 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 19 Jun 2023 17:21:50 +0100
+Subject: btrfs: fix race between quota disable and relocation
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 8a4a0b2a3eaf75ca8854f856ef29690c12b2f531 ]
+
+If we disable quotas while we have a relocation of a metadata block group
+that has extents belonging to the quota root, we can cause the relocation
+to fail with -ENOENT. This is because relocation builds backref nodes for
+extents of the quota root and later needs to walk the backrefs and access
+the quota root - however if in between a task disables quotas, it results
+in deleting the quota root from the root tree (with btrfs_del_root(),
+called from btrfs_quota_disable().
+
+This can be sporadically triggered by test case btrfs/255 from fstests:
+
+ $ ./check btrfs/255
+ FSTYP -- btrfs
+ PLATFORM -- Linux/x86_64 debian0 6.4.0-rc6-btrfs-next-134+ #1 SMP PREEMPT_DYNAMIC Thu Jun 15 11:59:28 WEST 2023
+ MKFS_OPTIONS -- /dev/sdc
+ MOUNT_OPTIONS -- /dev/sdc /home/fdmanana/btrfs-tests/scratch_1
+
+ btrfs/255 6s ... _check_dmesg: something found in dmesg (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.dmesg)
+ - output mismatch (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad)
+ --- tests/btrfs/255.out 2023-03-02 21:47:53.876609426 +0000
+ +++ /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad 2023-06-16 10:20:39.267563212 +0100
+ @@ -1,2 +1,4 @@
+ QA output created by 255
+ +ERROR: error during balancing '/home/fdmanana/btrfs-tests/scratch_1': No such file or directory
+ +There may be more info in syslog - try dmesg | tail
+ Silence is golden
+ ...
+ (Run 'diff -u /home/fdmanana/git/hub/xfstests/tests/btrfs/255.out /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad' to see the entire diff)
+ Ran: btrfs/255
+ Failures: btrfs/255
+ Failed 1 of 1 tests
+
+To fix this make the quota disable operation take the cleaner mutex, as
+relocation of a block group also takes this mutex. This is also what we
+do when deleting a subvolume/snapshot, we take the cleaner mutex in the
+cleaner kthread (at cleaner_kthread()) and then we call btrfs_del_root()
+at btrfs_drop_snapshot() while under the protection of the cleaner mutex.
+
+Fixes: bed92eae26cc ("Btrfs: qgroup implementation and prototypes")
+CC: stable@vger.kernel.org # 5.4+
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/qgroup.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index 360bf2522a871..2637d6b157ff9 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1232,12 +1232,23 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+ int ret = 0;
+
+ /*
+- * We need to have subvol_sem write locked, to prevent races between
+- * concurrent tasks trying to disable quotas, because we will unlock
+- * and relock qgroup_ioctl_lock across BTRFS_FS_QUOTA_ENABLED changes.
++ * We need to have subvol_sem write locked to prevent races with
++ * snapshot creation.
+ */
+ lockdep_assert_held_write(&fs_info->subvol_sem);
+
++ /*
++ * Lock the cleaner mutex to prevent races with concurrent relocation,
++ * because relocation may be building backrefs for blocks of the quota
++ * root while we are deleting the root. This is like dropping fs roots
++ * of deleted snapshots/subvolumes, we need the same protection.
++ *
++ * This also prevents races between concurrent tasks trying to disable
++ * quotas, because we will unlock and relock qgroup_ioctl_lock across
++ * BTRFS_FS_QUOTA_ENABLED changes.
++ */
++ mutex_lock(&fs_info->cleaner_mutex);
++
+ mutex_lock(&fs_info->qgroup_ioctl_lock);
+ if (!fs_info->quota_root)
+ goto out;
+@@ -1319,6 +1330,7 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+ btrfs_end_transaction(trans);
+ else if (trans)
+ ret = btrfs_end_transaction(trans);
++ mutex_unlock(&fs_info->cleaner_mutex);
+
+ return ret;
+ }
+--
+2.39.2
+
--- /dev/null
+From a361a41bb59e91868ba18927940620ed34fb9f16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Mar 2023 14:29:52 -0600
+Subject: drm/amd/display: Add FAMS validation before trying to use it
+
+From: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+
+[ Upstream commit e3416e872f84086667df21daf166506fab97358d ]
+
+To ensure that FAMS can be used, DC must check if there is VRR support.
+This commit adds the required configuration to ensure FAMS can be executed in the target system.
+
+Reviewed-by: Alvin Lee <Alvin.Lee2@amd.com>
+Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
+Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: 2a9482e55968 ("drm/amd/display: Prevent vtotal from being set to 0")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 6 ++++++
+ drivers/gpu/drm/amd/display/dc/dc_stream.h | 1 +
+ drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c | 7 ++++++-
+ drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 2 +-
+ 4 files changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 6eace83c9c6f5..7f6bdad57c920 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -2626,6 +2626,12 @@ static enum surface_update_type check_update_surfaces_for_stream(
+
+ if (stream_update->mst_bw_update)
+ su_flags->bits.mst_bw = 1;
++
++ if (stream_update->stream && stream_update->stream->freesync_on_desktop &&
++ (stream_update->vrr_infopacket || stream_update->allow_freesync ||
++ stream_update->vrr_active_variable))
++ su_flags->bits.fams_changed = 1;
++
+ if (stream_update->crtc_timing_adjust && dc_extended_blank_supported(dc))
+ su_flags->bits.crtc_timing_adjust = 1;
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
+index 25284006019c3..270282fbda4ab 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
+@@ -131,6 +131,7 @@ union stream_update_flags {
+ uint32_t dsc_changed : 1;
+ uint32_t mst_bw : 1;
+ uint32_t crtc_timing_adjust : 1;
++ uint32_t fams_changed : 1;
+ } bits;
+
+ uint32_t raw;
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
+index c95f000b63b28..34b08d90dc1da 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
+@@ -301,7 +301,12 @@ static void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *o
+
+ void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max)
+ {
+- optc1_set_vtotal_min_max(optc, vtotal_min, vtotal_max);
++ struct dc *dc = optc->ctx->dc;
++
++ if (dc->caps.dmub_caps.mclk_sw && !dc->debug.disable_fams)
++ dc_dmub_srv_drr_update_cmd(dc, optc->inst, vtotal_min, vtotal_max);
++ else
++ optc1_set_vtotal_min_max(optc, vtotal_min, vtotal_max);
+ }
+
+ void optc3_tg_init(struct timing_generator *optc)
+diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+index 598fa1de54ce3..1c55d3b01f53e 100644
+--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
++++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+@@ -360,7 +360,7 @@ union dmub_fw_boot_status {
+ uint32_t optimized_init_done : 1; /**< 1 if optimized init done */
+ uint32_t restore_required : 1; /**< 1 if driver should call restore */
+ uint32_t defer_load : 1; /**< 1 if VBIOS data is deferred programmed */
+- uint32_t reserved : 1;
++ uint32_t fams_enabled : 1; /**< 1 if VBIOS data is deferred programmed */
+ uint32_t detection_required: 1; /**< if detection need to be triggered by driver */
+ uint32_t hw_power_init_done: 1; /**< 1 if hw power init is completed */
+ } bits; /**< status bits */
+--
+2.39.2
+
--- /dev/null
+From e59520e6c320738c4e31f10bfbd1ea83b27fefb2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Dec 2022 15:13:18 -0500
+Subject: drm/amd/display: add pixel rate based CRB allocation support
+
+From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
+
+[ Upstream commit 9ba90d760e9354c124fa9bbea08017d96699a82c ]
+
+This feature is meant to unblock PSTATE for certain high end display
+configs on dcn315. This is achieved by allocating CRB to detile buffer
+based on display requirements to meet pstate latency hiding needs.
+
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Reviewed-by: Charlene Liu <Charlene.Liu@amd.com>
+Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: 49f26218c344 ("drm/amd/display: fix dcn315 single stream crb allocation")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../drm/amd/display/dc/dcn31/dcn31_hubbub.c | 1 +
+ .../amd/display/dc/dcn315/dcn315_resource.c | 97 ++++++++++++++++++-
+ .../drm/amd/display/dc/dml/dcn31/dcn31_fpu.c | 25 ++++-
+ .../drm/amd/display/dc/dml/dcn31/dcn31_fpu.h | 3 +
+ .../dc/dml/dcn31/display_mode_vba_31.c | 39 +++++---
+ .../drm/amd/display/dc/dml/display_mode_vba.c | 6 ++
+ 6 files changed, 154 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
+index 7e7cd5b64e6a1..7445ed27852a1 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
+@@ -103,6 +103,7 @@ static void dcn31_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigne
+ default:
+ break;
+ }
++ DC_LOG_DEBUG("Set DET%d to %d segments\n", hubp_inst, det_size_segments);
+ /* Should never be hit, if it is we have an erroneous hw config*/
+ ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size
+ + hubbub2->det3_size + hubbub2->compbuf_size_segments <= hubbub2->crb_size_segs);
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
+index 41c972c8eb198..42a0157fd8133 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
+@@ -136,6 +136,9 @@
+
+ #define DCN3_15_MAX_DET_SIZE 384
+ #define DCN3_15_CRB_SEGMENT_SIZE_KB 64
++#define DCN3_15_MAX_DET_SEGS (DCN3_15_MAX_DET_SIZE / DCN3_15_CRB_SEGMENT_SIZE_KB)
++/* Minimum 2 extra segments need to be in compbuf and claimable to guarantee seamless mpo transitions */
++#define MIN_RESERVED_DET_SEGS 2
+
+ enum dcn31_clk_src_array_id {
+ DCN31_CLK_SRC_PLL0,
+@@ -1636,21 +1639,57 @@ static bool is_dual_plane(enum surface_pixel_format format)
+ return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
+ }
+
++static int source_format_to_bpp (enum source_format_class SourcePixelFormat)
++{
++ if (SourcePixelFormat == dm_444_64)
++ return 8;
++ else if (SourcePixelFormat == dm_444_16 || SourcePixelFormat == dm_444_16)
++ return 2;
++ else if (SourcePixelFormat == dm_444_8)
++ return 1;
++ else if (SourcePixelFormat == dm_rgbe_alpha)
++ return 5;
++ else if (SourcePixelFormat == dm_420_8)
++ return 3;
++ else if (SourcePixelFormat == dm_420_12)
++ return 6;
++ else
++ return 4;
++}
++
++static bool allow_pixel_rate_crb(struct dc *dc, struct dc_state *context)
++{
++ int i;
++ struct resource_context *res_ctx = &context->res_ctx;
++
++ for (i = 0; i < dc->res_pool->pipe_count; i++) {
++ if (!res_ctx->pipe_ctx[i].stream)
++ continue;
++
++ /*Don't apply if MPO to avoid transition issues*/
++ if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state != res_ctx->pipe_ctx[i].plane_state)
++ return false;
++ }
++ return true;
++}
++
+ static int dcn315_populate_dml_pipes_from_context(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate)
+ {
+- int i, pipe_cnt;
++ int i, pipe_cnt, crb_idx, crb_pipes;
+ struct resource_context *res_ctx = &context->res_ctx;
+ struct pipe_ctx *pipe;
+ const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_15_MIN_COMPBUF_SIZE_KB;
++ int remaining_det_segs = max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB;
++ bool pixel_rate_crb = allow_pixel_rate_crb(dc, context);
+
+ DC_FP_START();
+ dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ DC_FP_END();
+
+- for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
++ for (i = 0, pipe_cnt = 0, crb_pipes = 0; i < dc->res_pool->pipe_count; i++) {
+ struct dc_crtc_timing *timing;
+
+ if (!res_ctx->pipe_ctx[i].stream)
+@@ -1671,6 +1710,23 @@ static int dcn315_populate_dml_pipes_from_context(
+ pipes[pipe_cnt].dout.dsc_input_bpc = 0;
+ DC_FP_START();
+ dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt);
++ if (pixel_rate_crb && !pipe->top_pipe && !pipe->prev_odm_pipe) {
++ int bpp = source_format_to_bpp(pipes[pipe_cnt].pipe.src.source_format);
++ /* Ceil to crb segment size */
++ int approx_det_segs_required_for_pstate = dcn_get_approx_det_segs_required_for_pstate(
++ &context->bw_ctx.dml.soc, timing->pix_clk_100hz, bpp, DCN3_15_CRB_SEGMENT_SIZE_KB);
++ if (approx_det_segs_required_for_pstate <= 2 * DCN3_15_MAX_DET_SEGS) {
++ bool split_required = approx_det_segs_required_for_pstate > DCN3_15_MAX_DET_SEGS;
++ split_required = split_required || timing->pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc);
++ split_required = split_required || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120);
++ if (split_required)
++ approx_det_segs_required_for_pstate += approx_det_segs_required_for_pstate % 2;
++ pipes[pipe_cnt].pipe.src.det_size_override = approx_det_segs_required_for_pstate;
++ remaining_det_segs -= approx_det_segs_required_for_pstate;
++ } else
++ remaining_det_segs = -1;
++ crb_pipes++;
++ }
+ DC_FP_END();
+
+ if (pipes[pipe_cnt].dout.dsc_enable) {
+@@ -1689,16 +1745,49 @@ static int dcn315_populate_dml_pipes_from_context(
+ break;
+ }
+ }
+-
+ pipe_cnt++;
+ }
+
++ /* Spread remaining unreserved crb evenly among all pipes, use default policy if not enough det or single pipe */
++ if (pixel_rate_crb) {
++ for (i = 0, pipe_cnt = 0, crb_idx = 0; i < dc->res_pool->pipe_count; i++) {
++ pipe = &res_ctx->pipe_ctx[i];
++ if (!pipe->stream)
++ continue;
++
++ if (!pipe->top_pipe && !pipe->prev_odm_pipe) {
++ bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc)
++ || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120);
++
++ if (remaining_det_segs < 0 || crb_pipes == 1)
++ pipes[pipe_cnt].pipe.src.det_size_override = 0;
++ if (remaining_det_segs > MIN_RESERVED_DET_SEGS)
++ pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes +
++ (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0);
++ if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) {
++ /* Clamp to 2 pipe split max det segments */
++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS);
++ pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS;
++ }
++ if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) {
++ /* If we are splitting we must have an even number of segments */
++ remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2;
++ pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2;
++ }
++ /* Convert segments into size for DML use */
++ pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB;
++ crb_idx++;
++ }
++ pipe_cnt++;
++ }
++ }
++
+ if (pipe_cnt)
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes =
+ (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / pipe_cnt) * DCN3_15_CRB_SEGMENT_SIZE_KB;
+ if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_15_MAX_DET_SIZE)
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_15_MAX_DET_SIZE;
+- ASSERT(context->bw_ctx.dml.ip.det_buffer_size_kbytes >= DCN3_15_DEFAULT_DET_SIZE);
++
+ dc->config.enable_4to1MPC = false;
+ if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) {
+ if (is_dual_plane(pipe->plane_state->format)
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
+index 59836570603ac..19d034341e640 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
+@@ -483,7 +483,7 @@ void dcn31_calculate_wm_and_dlg_fp(
+ int pipe_cnt,
+ int vlevel)
+ {
+- int i, pipe_idx, active_hubp_count = 0;
++ int i, pipe_idx, total_det = 0, active_hubp_count = 0;
+ double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
+
+ dc_assert_fp_enabled();
+@@ -563,6 +563,18 @@ void dcn31_calculate_wm_and_dlg_fp(
+ if (context->res_ctx.pipe_ctx[i].stream)
+ context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = 0;
+ }
++ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
++ if (!context->res_ctx.pipe_ctx[i].stream)
++ continue;
++
++ context->res_ctx.pipe_ctx[i].det_buffer_size_kb =
++ get_det_buffer_size_kbytes(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
++ if (context->res_ctx.pipe_ctx[i].det_buffer_size_kb > 384)
++ context->res_ctx.pipe_ctx[i].det_buffer_size_kb /= 2;
++ total_det += context->res_ctx.pipe_ctx[i].det_buffer_size_kb;
++ pipe_idx++;
++ }
++ context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - total_det;
+ }
+
+ void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+@@ -815,3 +827,14 @@ int dcn_get_max_non_odm_pix_rate_100hz(struct _vcs_dpi_soc_bounding_box_st *soc)
+ {
+ return soc->clock_limits[0].dispclk_mhz * 10000.0 / (1.0 + soc->dcn_downspread_percent / 100.0);
+ }
++
++int dcn_get_approx_det_segs_required_for_pstate(
++ struct _vcs_dpi_soc_bounding_box_st *soc,
++ int pix_clk_100hz, int bpp, int seg_size_kb)
++{
++ /* Roughly calculate required crb to hide latency. In practice there is slightly
++ * more buffer available for latency hiding
++ */
++ return (int)(soc->dram_clock_change_latency_us * pix_clk_100hz * bpp
++ / 10240000 + seg_size_kb - 1) / seg_size_kb;
++}
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
+index 687d3522cc33e..8f9c8faed2605 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
+@@ -47,6 +47,9 @@ void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params
+ void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+ void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+ int dcn_get_max_non_odm_pix_rate_100hz(struct _vcs_dpi_soc_bounding_box_st *soc);
++int dcn_get_approx_det_segs_required_for_pstate(
++ struct _vcs_dpi_soc_bounding_box_st *soc,
++ int pix_clk_100hz, int bpp, int seg_size_kb);
+
+ int dcn31x_populate_dml_pipes_from_context(struct dc *dc,
+ struct dc_state *context,
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
+index bd674dc30df33..a0f44eef7763f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
+@@ -532,7 +532,8 @@ static void CalculateStutterEfficiency(
+ static void CalculateSwathAndDETConfiguration(
+ bool ForceSingleDPP,
+ int NumberOfActivePlanes,
+- unsigned int DETBufferSizeInKByte,
++ bool DETSharedByAllDPP,
++ unsigned int DETBufferSizeInKByte[],
+ double MaximumSwathWidthLuma[],
+ double MaximumSwathWidthChroma[],
+ enum scan_direction_class SourceScan[],
+@@ -3118,7 +3119,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
+ v->SurfaceWidthC[k],
+ v->SurfaceHeightY[k],
+ v->SurfaceHeightC[k],
+- v->DETBufferSizeInKByte[0] * 1024,
++ v->DETBufferSizeInKByte[k] * 1024,
+ v->BlockHeight256BytesY[k],
+ v->BlockHeight256BytesC[k],
+ v->SurfaceTiling[k],
+@@ -3313,7 +3314,8 @@ static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib)
+ CalculateSwathAndDETConfiguration(
+ false,
+ v->NumberOfActivePlanes,
+- v->DETBufferSizeInKByte[0],
++ mode_lib->project == DML_PROJECT_DCN315 && v->DETSizeOverride[0],
++ v->DETBufferSizeInKByte,
+ dummy1,
+ dummy2,
+ v->SourceScan,
+@@ -3779,14 +3781,16 @@ static noinline void CalculatePrefetchSchedulePerPlane(
+ &v->VReadyOffsetPix[k]);
+ }
+
+-static void PatchDETBufferSizeInKByte(unsigned int NumberOfActivePlanes, int NoOfDPPThisState[], unsigned int config_return_buffer_size_in_kbytes, unsigned int *DETBufferSizeInKByte)
++static void PatchDETBufferSizeInKByte(unsigned int NumberOfActivePlanes, int NoOfDPPThisState[], unsigned int config_return_buffer_size_in_kbytes, unsigned int DETBufferSizeInKByte[])
+ {
+ int i, total_pipes = 0;
+ for (i = 0; i < NumberOfActivePlanes; i++)
+ total_pipes += NoOfDPPThisState[i];
+- *DETBufferSizeInKByte = ((config_return_buffer_size_in_kbytes - DCN3_15_MIN_COMPBUF_SIZE_KB) / 64 / total_pipes) * 64;
+- if (*DETBufferSizeInKByte > DCN3_15_MAX_DET_SIZE)
+- *DETBufferSizeInKByte = DCN3_15_MAX_DET_SIZE;
++ DETBufferSizeInKByte[0] = ((config_return_buffer_size_in_kbytes - DCN3_15_MIN_COMPBUF_SIZE_KB) / 64 / total_pipes) * 64;
++ if (DETBufferSizeInKByte[0] > DCN3_15_MAX_DET_SIZE)
++ DETBufferSizeInKByte[0] = DCN3_15_MAX_DET_SIZE;
++ for (i = 1; i < NumberOfActivePlanes; i++)
++ DETBufferSizeInKByte[i] = DETBufferSizeInKByte[0];
+ }
+
+
+@@ -4026,7 +4030,8 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
+ CalculateSwathAndDETConfiguration(
+ true,
+ v->NumberOfActivePlanes,
+- v->DETBufferSizeInKByte[0],
++ mode_lib->project == DML_PROJECT_DCN315 && v->DETSizeOverride[0],
++ v->DETBufferSizeInKByte,
+ v->MaximumSwathWidthLuma,
+ v->MaximumSwathWidthChroma,
+ v->SourceScan,
+@@ -4166,6 +4171,10 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
+ || (v->PlaneRequiredDISPCLK > v->MaxDispclkRoundedDownToDFSGranularity)) {
+ v->DISPCLK_DPPCLK_Support[i][j] = false;
+ }
++ if (mode_lib->project == DML_PROJECT_DCN315 && v->DETSizeOverride[k] > DCN3_15_MAX_DET_SIZE && v->NoOfDPP[i][j][k] < 2) {
++ v->MPCCombine[i][j][k] = true;
++ v->NoOfDPP[i][j][k] = 2;
++ }
+ }
+ v->TotalNumberOfActiveDPP[i][j] = 0;
+ v->TotalNumberOfSingleDPPPlanes[i][j] = 0;
+@@ -4642,12 +4651,13 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
+ v->ODMCombineEnableThisState[k] = v->ODMCombineEnablePerState[i][k];
+ }
+
+- if (v->NumberOfActivePlanes > 1 && mode_lib->project == DML_PROJECT_DCN315)
+- PatchDETBufferSizeInKByte(v->NumberOfActivePlanes, v->NoOfDPPThisState, v->ip.config_return_buffer_size_in_kbytes, &v->DETBufferSizeInKByte[0]);
++ if (v->NumberOfActivePlanes > 1 && mode_lib->project == DML_PROJECT_DCN315 && !v->DETSizeOverride[0])
++ PatchDETBufferSizeInKByte(v->NumberOfActivePlanes, v->NoOfDPPThisState, v->ip.config_return_buffer_size_in_kbytes, v->DETBufferSizeInKByte);
+ CalculateSwathAndDETConfiguration(
+ false,
+ v->NumberOfActivePlanes,
+- v->DETBufferSizeInKByte[0],
++ mode_lib->project == DML_PROJECT_DCN315 && v->DETSizeOverride[0],
++ v->DETBufferSizeInKByte,
+ v->MaximumSwathWidthLuma,
+ v->MaximumSwathWidthChroma,
+ v->SourceScan,
+@@ -6611,7 +6621,8 @@ static void CalculateStutterEfficiency(
+ static void CalculateSwathAndDETConfiguration(
+ bool ForceSingleDPP,
+ int NumberOfActivePlanes,
+- unsigned int DETBufferSizeInKByte,
++ bool DETSharedByAllDPP,
++ unsigned int DETBufferSizeInKByteA[],
+ double MaximumSwathWidthLuma[],
+ double MaximumSwathWidthChroma[],
+ enum scan_direction_class SourceScan[],
+@@ -6695,6 +6706,10 @@ static void CalculateSwathAndDETConfiguration(
+
+ *ViewportSizeSupport = true;
+ for (k = 0; k < NumberOfActivePlanes; ++k) {
++ unsigned int DETBufferSizeInKByte = DETBufferSizeInKByteA[k];
++
++ if (DETSharedByAllDPP && DPPPerPlane[k])
++ DETBufferSizeInKByte /= DPPPerPlane[k];
+ if ((SourcePixelFormat[k] == dm_444_64 || SourcePixelFormat[k] == dm_444_32 || SourcePixelFormat[k] == dm_444_16 || SourcePixelFormat[k] == dm_mono_16
+ || SourcePixelFormat[k] == dm_mono_8 || SourcePixelFormat[k] == dm_rgbe)) {
+ if (SurfaceTiling[k] == dm_sw_linear
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
+index f9653f511baa3..2f63ae954826c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
+@@ -571,6 +571,10 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib)
+ mode_lib->vba.OutputLinkDPRate[mode_lib->vba.NumberOfActivePlanes] = dout->dp_rate;
+ mode_lib->vba.ODMUse[mode_lib->vba.NumberOfActivePlanes] = dst->odm_combine_policy;
+ mode_lib->vba.DETSizeOverride[mode_lib->vba.NumberOfActivePlanes] = src->det_size_override;
++ if (src->det_size_override)
++ mode_lib->vba.DETBufferSizeInKByte[mode_lib->vba.NumberOfActivePlanes] = src->det_size_override;
++ else
++ mode_lib->vba.DETBufferSizeInKByte[mode_lib->vba.NumberOfActivePlanes] = ip->det_buffer_size_kbytes;
+ //TODO: Need to assign correct values to dp_multistream vars
+ mode_lib->vba.OutputMultistreamEn[mode_lib->vba.NumberOfActiveSurfaces] = dout->dp_multistream_en;
+ mode_lib->vba.OutputMultistreamId[mode_lib->vba.NumberOfActiveSurfaces] = dout->dp_multistream_id;
+@@ -785,6 +789,8 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib)
+ mode_lib->vba.pipe_plane[k] =
+ mode_lib->vba.NumberOfActivePlanes;
+ mode_lib->vba.DPPPerPlane[mode_lib->vba.NumberOfActivePlanes]++;
++ if (src_k->det_size_override)
++ mode_lib->vba.DETBufferSizeInKByte[mode_lib->vba.NumberOfActivePlanes] = src_k->det_size_override;
+ if (mode_lib->vba.SourceScan[mode_lib->vba.NumberOfActivePlanes]
+ == dm_horz) {
+ mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] +=
+--
+2.39.2
+
--- /dev/null
+From 8a4b47967da090ae66ec4d685fe677627f56b116 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Apr 2023 11:43:50 -0400
+Subject: drm/amd/display: Convert Delaying Aux-I Disable To Monitor Patch
+
+From: Michael Strauss <michael.strauss@amd.com>
+
+[ Upstream commit 9fa8cc0c444562fa19e20ca20f1c70e15b9d8c13 ]
+
+[WHY]
+32ms delay was added to resolve issue with a specific sink, however this same
+delay also introduces erroneous link training failures with certain sink
+devices.
+
+[HOW]
+Only apply the 32ms delay for offending devices instead of globally.
+
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Reviewed-by: Jun Lei <Jun.Lei@amd.com>
+Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Signed-off-by: Michael Strauss <michael.strauss@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: 5a096b73c8fe ("drm/amd/display: Keep disable aux-i delay as 0")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dc.h | 1 -
+ drivers/gpu/drm/amd/display/dc/dc_types.h | 1 +
+ .../link_dp_training_fixed_vs_pe_retimer.c | 17 +++++++++++------
+ 3 files changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
+index 4d93ca9c627b0..07d86b961c798 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc.h
++++ b/drivers/gpu/drm/amd/display/dc/dc.h
+@@ -855,7 +855,6 @@ struct dc_debug_options {
+ bool force_usr_allow;
+ /* uses value at boot and disables switch */
+ bool disable_dtb_ref_clk_switch;
+- uint32_t fixed_vs_aux_delay_config_wa;
+ bool extended_blank_optimization;
+ union aux_wake_wa_options aux_wake_wa;
+ uint32_t mst_start_top_delay;
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
+index 45ab48fe5d004..139a77acd5d02 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
+@@ -196,6 +196,7 @@ struct dc_panel_patch {
+ unsigned int disable_fams;
+ unsigned int skip_avmute;
+ unsigned int mst_start_top_delay;
++ unsigned int delay_disable_aux_intercept_ms;
+ };
+
+ struct dc_edid_caps {
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
+index 5731c4b61f9f0..fb6c938c6dab1 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
+@@ -233,7 +233,8 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
+ const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
+- uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
++ uint32_t pre_disable_intercept_delay_ms =
++ link->local_sink->edid_caps.panel_patch.delay_disable_aux_intercept_ms;
+ uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+ uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
+ uint32_t vendor_lttpr_write_address = 0xF004F;
+@@ -259,7 +260,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
+
+ /* Certain display and cable configuration require extra delay */
+ if (offset > 2)
+- pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
++ pre_disable_intercept_delay_ms = pre_disable_intercept_delay_ms * 2;
+ }
+
+ /* Vendor specific: Reset lane settings */
+@@ -380,7 +381,8 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
+ 0);
+ /* Vendor specific: Disable intercept */
+ for (i = 0; i < max_vendor_dpcd_retries; i++) {
+- msleep(pre_disable_intercept_delay_ms);
++ if (pre_disable_intercept_delay_ms != 0)
++ msleep(pre_disable_intercept_delay_ms);
+ dpcd_status = core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+@@ -591,9 +593,11 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+ const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E};
+ const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01};
+ const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
+- uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
+ uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+ uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
++ uint32_t pre_disable_intercept_delay_ms =
++ link->local_sink->edid_caps.panel_patch.delay_disable_aux_intercept_ms;
++
+
+ uint32_t vendor_lttpr_write_address = 0xF004F;
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+@@ -618,7 +622,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+
+ /* Certain display and cable configuration require extra delay */
+ if (offset > 2)
+- pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
++ pre_disable_intercept_delay_ms = pre_disable_intercept_delay_ms * 2;
+ }
+
+ /* Vendor specific: Reset lane settings */
+@@ -739,7 +743,8 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+ 0);
+ /* Vendor specific: Disable intercept */
+ for (i = 0; i < max_vendor_dpcd_retries; i++) {
+- msleep(pre_disable_intercept_delay_ms);
++ if (pre_disable_intercept_delay_ms != 0)
++ msleep(pre_disable_intercept_delay_ms);
+ dpcd_status = core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+--
+2.39.2
+
--- /dev/null
+From bfaca573c34e5c1632c7d88930ef4067d398f550 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 15:50:40 -0400
+Subject: drm/amd/display: fix dcn315 single stream crb allocation
+
+From: Dmytro Laktyushkin <dmytro.laktyushkin@amd.com>
+
+[ Upstream commit 49f26218c344741cb3eaa740b1e44e960551a87f ]
+
+Change to improve avoiding asymetric crb calculations for single stream
+scenarios.
+
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Acked-by: Stylon Wang <stylon.wang@amd.com>
+Signed-off-by: Dmytro Laktyushkin <dmytro.laktyushkin@amd.com>
+Reviewed-by: Charlene Liu <Charlene.Liu@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../drm/amd/display/dc/dcn315/dcn315_resource.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
+index 42a0157fd8133..ae99b2851e019 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
+@@ -1662,6 +1662,10 @@ static bool allow_pixel_rate_crb(struct dc *dc, struct dc_state *context)
+ int i;
+ struct resource_context *res_ctx = &context->res_ctx;
+
++ /*Don't apply for single stream*/
++ if (context->stream_count < 2)
++ return false;
++
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ if (!res_ctx->pipe_ctx[i].stream)
+ continue;
+@@ -1748,19 +1752,23 @@ static int dcn315_populate_dml_pipes_from_context(
+ pipe_cnt++;
+ }
+
+- /* Spread remaining unreserved crb evenly among all pipes, use default policy if not enough det or single pipe */
++ /* Spread remaining unreserved crb evenly among all pipes*/
+ if (pixel_rate_crb) {
+ for (i = 0, pipe_cnt = 0, crb_idx = 0; i < dc->res_pool->pipe_count; i++) {
+ pipe = &res_ctx->pipe_ctx[i];
+ if (!pipe->stream)
+ continue;
+
++ /* Do not use asymetric crb if not enough for pstate support */
++ if (remaining_det_segs < 0) {
++ pipes[pipe_cnt].pipe.src.det_size_override = 0;
++ continue;
++ }
++
+ if (!pipe->top_pipe && !pipe->prev_odm_pipe) {
+ bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc)
+ || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120);
+
+- if (remaining_det_segs < 0 || crb_pipes == 1)
+- pipes[pipe_cnt].pipe.src.det_size_override = 0;
+ if (remaining_det_segs > MIN_RESERVED_DET_SEGS)
+ pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes +
+ (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0);
+@@ -1776,6 +1784,7 @@ static int dcn315_populate_dml_pipes_from_context(
+ }
+ /* Convert segments into size for DML use */
+ pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB;
++
+ crb_idx++;
+ }
+ pipe_cnt++;
+--
+2.39.2
+
--- /dev/null
+From 04a62bd458bc032a71edbb5273ebbd4d406be41f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Apr 2023 14:29:48 -0400
+Subject: drm/amd/display: Fix possible underflow for displays with large
+ vblank
+
+From: Daniel Miess <daniel.miess@amd.com>
+
+[ Upstream commit 1a4bcdbea4319efeb26cc4b05be859a7867e02dc ]
+
+[Why]
+Underflow observed when using a display with a large vblank region
+and low refresh rate
+
+[How]
+Simplify calculation of vblank_nom
+
+Increase value for VBlankNomDefaultUS to 800us
+
+Reviewed-by: Jun Lei <jun.lei@amd.com>
+Acked-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Signed-off-by: Daniel Miess <daniel.miess@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: 2a9482e55968 ("drm/amd/display: Prevent vtotal from being set to 0")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/display/dc/dml/dcn314/dcn314_fpu.c | 19 +++++++------------
+ 1 file changed, 7 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+index 1d00eb9e73c62..554152371eb53 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+@@ -33,7 +33,7 @@
+ #include "dml/display_mode_vba.h"
+
+ struct _vcs_dpi_ip_params_st dcn3_14_ip = {
+- .VBlankNomDefaultUS = 668,
++ .VBlankNomDefaultUS = 800,
+ .gpuvm_enable = 1,
+ .gpuvm_max_page_table_levels = 1,
+ .hostvm_enable = 1,
+@@ -286,7 +286,7 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
+ struct resource_context *res_ctx = &context->res_ctx;
+ struct pipe_ctx *pipe;
+ bool upscaled = false;
+- bool isFreesyncVideo = false;
++ const unsigned int max_allowed_vblank_nom = 1023;
+
+ dc_assert_fp_enabled();
+
+@@ -300,16 +300,11 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
+ pipe = &res_ctx->pipe_ctx[i];
+ timing = &pipe->stream->timing;
+
+- isFreesyncVideo = pipe->stream->adjust.v_total_max == pipe->stream->adjust.v_total_min;
+- isFreesyncVideo = isFreesyncVideo && pipe->stream->adjust.v_total_min > timing->v_total;
+-
+- if (!isFreesyncVideo) {
+- pipes[pipe_cnt].pipe.dest.vblank_nom =
+- dcn3_14_ip.VBlankNomDefaultUS / (timing->h_total / (timing->pix_clk_100hz / 10000.0));
+- } else {
+- pipes[pipe_cnt].pipe.dest.vtotal = pipe->stream->adjust.v_total_min;
+- pipes[pipe_cnt].pipe.dest.vblank_nom = timing->v_total - pipes[pipe_cnt].pipe.dest.vactive;
+- }
++ pipes[pipe_cnt].pipe.dest.vtotal = pipe->stream->adjust.v_total_min;
++ pipes[pipe_cnt].pipe.dest.vblank_nom = timing->v_total - pipes[pipe_cnt].pipe.dest.vactive;
++ pipes[pipe_cnt].pipe.dest.vblank_nom = min(pipes[pipe_cnt].pipe.dest.vblank_nom, dcn3_14_ip.VBlankNomDefaultUS);
++ pipes[pipe_cnt].pipe.dest.vblank_nom = max(pipes[pipe_cnt].pipe.dest.vblank_nom, timing->v_sync_width);
++ pipes[pipe_cnt].pipe.dest.vblank_nom = min(pipes[pipe_cnt].pipe.dest.vblank_nom, max_allowed_vblank_nom);
+
+ if (pipe->plane_state &&
+ (pipe->plane_state->src_rect.height < pipe->plane_state->dst_rect.height ||
+--
+2.39.2
+
--- /dev/null
+From 6142b2fae36f3f9c6169ef616cd3de2430258b62 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Apr 2023 12:44:54 -0400
+Subject: drm/amd/display: Keep disable aux-i delay as 0
+
+From: Michael Strauss <michael.strauss@amd.com>
+
+[ Upstream commit 5a096b73c8fed3a9987ba15378285df360e2284b ]
+
+[WHY]
+Current Aux-I sequence checks for local_sink which isn't populated on
+MST links
+
+[HOW]
+Leave disable aux-i delay as 0 for MST cases
+
+Cc: stable@vger.kernel.org
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Reviewed-by: George Shen <George.Shen@amd.com>
+Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
+Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Signed-off-by: Michael Strauss <michael.strauss@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../link_dp_training_fixed_vs_pe_retimer.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
+index fb6c938c6dab1..15faaf645b145 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
+@@ -233,8 +233,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
+ const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
+- uint32_t pre_disable_intercept_delay_ms =
+- link->local_sink->edid_caps.panel_patch.delay_disable_aux_intercept_ms;
++ uint32_t pre_disable_intercept_delay_ms = 0;
+ uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+ uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
+ uint32_t vendor_lttpr_write_address = 0xF004F;
+@@ -245,6 +244,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy(
+ uint8_t toggle_rate;
+ uint8_t rate;
+
++ if (link->local_sink)
++ pre_disable_intercept_delay_ms =
++ link->local_sink->edid_caps.panel_patch.delay_disable_aux_intercept_ms;
++
+ /* Only 8b/10b is supported */
+ ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
+ DP_8b_10b_ENCODING);
+@@ -595,10 +598,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+ const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
+ uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+ uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
+- uint32_t pre_disable_intercept_delay_ms =
+- link->local_sink->edid_caps.panel_patch.delay_disable_aux_intercept_ms;
+-
+-
++ uint32_t pre_disable_intercept_delay_ms = 0;
+ uint32_t vendor_lttpr_write_address = 0xF004F;
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ uint8_t lane = 0;
+@@ -607,6 +607,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+ uint8_t toggle_rate;
+ uint8_t rate;
+
++ if (link->local_sink)
++ pre_disable_intercept_delay_ms =
++ link->local_sink->edid_caps.panel_patch.delay_disable_aux_intercept_ms;
++
+ /* Only 8b/10b is supported */
+ ASSERT(link_dp_get_encoding_format(<_settings->link_settings) ==
+ DP_8b_10b_ENCODING);
+--
+2.39.2
+
--- /dev/null
+From 5f0e6cead38f98325242410ead912387ac08fa22 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Jun 2023 08:11:48 -0400
+Subject: drm/amd/display: Prevent vtotal from being set to 0
+
+From: Daniel Miess <daniel.miess@amd.com>
+
+[ Upstream commit 2a9482e55968ed7368afaa9c2133404069117320 ]
+
+[Why]
+In dcn314 DML the destination pipe vtotal was being set
+to the crtc adjustment vtotal_min value even in cases
+where that value is 0.
+
+[How]
+Only set vtotal to the crtc adjustment vtotal_min value
+in cases where the value is non-zero.
+
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Acked-by: Alan Liu <haoping.liu@amd.com>
+Signed-off-by: Daniel Miess <daniel.miess@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+index 554152371eb53..b878effa2129b 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+@@ -300,7 +300,11 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
+ pipe = &res_ctx->pipe_ctx[i];
+ timing = &pipe->stream->timing;
+
+- pipes[pipe_cnt].pipe.dest.vtotal = pipe->stream->adjust.v_total_min;
++ if (pipe->stream->adjust.v_total_min != 0)
++ pipes[pipe_cnt].pipe.dest.vtotal = pipe->stream->adjust.v_total_min;
++ else
++ pipes[pipe_cnt].pipe.dest.vtotal = timing->v_total;
++
+ pipes[pipe_cnt].pipe.dest.vblank_nom = timing->v_total - pipes[pipe_cnt].pipe.dest.vactive;
+ pipes[pipe_cnt].pipe.dest.vblank_nom = min(pipes[pipe_cnt].pipe.dest.vblank_nom, dcn3_14_ip.VBlankNomDefaultUS);
+ pipes[pipe_cnt].pipe.dest.vblank_nom = max(pipes[pipe_cnt].pipe.dest.vblank_nom, timing->v_sync_width);
+--
+2.39.2
+
--- /dev/null
+From 28965cbdb2318bc2d4453590d56da2b851c98085 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Jun 2023 10:05:20 -0500
+Subject: drm/amd/display: Set minimum requirement for using PSR-SU on
+ Rembrandt
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+[ Upstream commit c35b6ea8f2ecfa9d775530b70d4e727869099a9c ]
+
+A number of parade TCONs are causing system hangs when utilized with
+older DMUB firmware and PSR-SU. Some changes have been introduced into
+DMUB firmware to add resilience against these failures.
+
+Don't allow running PSR-SU unless on the newer firmware.
+
+Cc: stable@vger.kernel.org
+Cc: Sean Wang <sean.ns.wang@amd.com>
+Cc: Marc Rossi <Marc.Rossi@amd.com>
+Cc: Hamza Mahfooz <Hamza.Mahfooz@amd.com>
+Cc: Tsung-hua (Ryan) Lin <Tsung-hua.Lin@amd.com>
+Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2443
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Reviewed-by: Leo Li <sunpeng.li@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: cd2e31a9ab93 ("drm/amd/display: Set minimum requirement for using PSR-SU on Phoenix")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c | 3 ++-
+ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 7 +++++++
+ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 1 +
+ drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 2 ++
+ drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 5 +++++
+ drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h | 2 ++
+ drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 10 ++++++----
+ 7 files changed, 25 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
+index d647f68fd5630..4f61d4f257cd7 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
+@@ -24,6 +24,7 @@
+ */
+
+ #include "amdgpu_dm_psr.h"
++#include "dc_dmub_srv.h"
+ #include "dc.h"
+ #include "dm_helpers.h"
+ #include "amdgpu_dm.h"
+@@ -50,7 +51,7 @@ static bool link_supports_psrsu(struct dc_link *link)
+ !link->dpcd_caps.psr_info.psr2_su_y_granularity_cap)
+ return false;
+
+- return true;
++ return dc_dmub_check_min_version(dc->ctx->dmub_srv->dmub);
+ }
+
+ /*
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+index a9b9490a532c2..ab4542b57b9a3 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
++++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+@@ -1079,3 +1079,10 @@ void dc_send_update_cursor_info_to_dmu(
+ dc_send_cmd_to_dmu(pCtx->stream->ctx->dmub_srv, &cmd);
+ }
+ }
++
++bool dc_dmub_check_min_version(struct dmub_srv *srv)
++{
++ if (!srv->hw_funcs.is_psrsu_supported)
++ return true;
++ return srv->hw_funcs.is_psrsu_supported(srv);
++}
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+index d34f5563df2ec..9a248ced03b9c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+@@ -89,4 +89,5 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, struct dc_state *context, b
+ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv);
+
+ void dc_send_update_cursor_info_to_dmu(struct pipe_ctx *pCtx, uint8_t pipe_idx);
++bool dc_dmub_check_min_version(struct dmub_srv *srv);
+ #endif /* _DMUB_DC_SRV_H_ */
+diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+index 554ab48d4e647..9cad599b27094 100644
+--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
++++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+@@ -364,6 +364,8 @@ struct dmub_srv_hw_funcs {
+
+ bool (*is_supported)(struct dmub_srv *dmub);
+
++ bool (*is_psrsu_supported)(struct dmub_srv *dmub);
++
+ bool (*is_hw_init)(struct dmub_srv *dmub);
+
+ bool (*is_phy_init)(struct dmub_srv *dmub);
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
+index c90b9ee42e126..89d24fb7024e2 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
+@@ -297,6 +297,11 @@ bool dmub_dcn31_is_supported(struct dmub_srv *dmub)
+ return supported;
+ }
+
++bool dmub_dcn31_is_psrsu_supported(struct dmub_srv *dmub)
++{
++ return dmub->fw_version >= DMUB_FW_VERSION(4, 0, 59);
++}
++
+ void dmub_dcn31_set_gpint(struct dmub_srv *dmub,
+ union dmub_gpint_data_register reg)
+ {
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
+index f6db6f89d45dc..eb62410941473 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
+@@ -219,6 +219,8 @@ bool dmub_dcn31_is_hw_init(struct dmub_srv *dmub);
+
+ bool dmub_dcn31_is_supported(struct dmub_srv *dmub);
+
++bool dmub_dcn31_is_psrsu_supported(struct dmub_srv *dmub);
++
+ void dmub_dcn31_set_gpint(struct dmub_srv *dmub,
+ union dmub_gpint_data_register reg);
+
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+index 6d76ce327d69f..0f43a05a41874 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+@@ -227,14 +227,16 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
+ case DMUB_ASIC_DCN314:
+ case DMUB_ASIC_DCN315:
+ case DMUB_ASIC_DCN316:
+- if (asic == DMUB_ASIC_DCN314)
++ if (asic == DMUB_ASIC_DCN314) {
+ dmub->regs_dcn31 = &dmub_srv_dcn314_regs;
+- else if (asic == DMUB_ASIC_DCN315)
++ } else if (asic == DMUB_ASIC_DCN315) {
+ dmub->regs_dcn31 = &dmub_srv_dcn315_regs;
+- else if (asic == DMUB_ASIC_DCN316)
++ } else if (asic == DMUB_ASIC_DCN316) {
+ dmub->regs_dcn31 = &dmub_srv_dcn316_regs;
+- else
++ } else {
+ dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
++ funcs->is_psrsu_supported = dmub_dcn31_is_psrsu_supported;
++ }
+ funcs->reset = dmub_dcn31_reset;
+ funcs->reset_release = dmub_dcn31_reset_release;
+ funcs->backdoor_load = dmub_dcn31_backdoor_load;
+--
+2.39.2
+
--- /dev/null
+From d623a4ddd0ae6bb52daf95849c1affbb334cf122 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Jun 2023 10:05:21 -0500
+Subject: drm/amd/display: Set minimum requirement for using PSR-SU on Phoenix
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+[ Upstream commit cd2e31a9ab93d13c412a36c6e26811e0f830985b ]
+
+The same parade TCON issue can potentially happen on Phoenix, and the same
+PSR resilience changes have been ported into the DMUB firmware.
+
+Don't allow running PSR-SU unless on the newer firmware.
+
+Cc: stable@vger.kernel.org
+Cc: Sean Wang <sean.ns.wang@amd.com>
+Cc: Marc Rossi <Marc.Rossi@amd.com>
+Cc: Hamza Mahfooz <Hamza.Mahfooz@amd.com>
+Cc: Tsung-hua (Ryan) Lin <Tsung-hua.Lin@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Reviewed-by: Leo Li <sunpeng.li@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c | 5 +++++
+ drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h | 2 ++
+ drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 1 +
+ 3 files changed, 8 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c
+index 48a06dbd9be78..f161aeb7e7c4a 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c
+@@ -60,3 +60,8 @@ const struct dmub_srv_dcn31_regs dmub_srv_dcn314_regs = {
+ { DMUB_DCN31_FIELDS() },
+ #undef DMUB_SF
+ };
++
++bool dmub_dcn314_is_psrsu_supported(struct dmub_srv *dmub)
++{
++ return dmub->fw_version >= DMUB_FW_VERSION(8, 0, 16);
++}
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h
+index 674267a2940e9..f213bd82c9110 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h
+@@ -30,4 +30,6 @@
+
+ extern const struct dmub_srv_dcn31_regs dmub_srv_dcn314_regs;
+
++bool dmub_dcn314_is_psrsu_supported(struct dmub_srv *dmub);
++
+ #endif /* _DMUB_DCN314_H_ */
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+index 0f43a05a41874..0dab22d794808 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+@@ -229,6 +229,7 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
+ case DMUB_ASIC_DCN316:
+ if (asic == DMUB_ASIC_DCN314) {
+ dmub->regs_dcn31 = &dmub_srv_dcn314_regs;
++ funcs->is_psrsu_supported = dmub_dcn314_is_psrsu_supported;
+ } else if (asic == DMUB_ASIC_DCN315) {
+ dmub->regs_dcn31 = &dmub_srv_dcn315_regs;
+ } else if (asic == DMUB_ASIC_DCN316) {
+--
+2.39.2
+
--- /dev/null
+From 98f1764121842a09e89c9a7fd64908ce78b3e45a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 May 2023 23:33:46 +0800
+Subject: drm/amd/display: Update correct DCN314 register header
+
+From: Cruise Hung <cruise.hung@amd.com>
+
+[ Upstream commit 268182606f26434c5d3ebd0e86efcb0418dec487 ]
+
+[Why]
+The register header for DCN314 is not correct.
+
+[How]
+Update correct DCN314 register header.
+
+Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Acked-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Cruise Hung <cruise.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: cd2e31a9ab93 ("drm/amd/display: Set minimum requirement for using PSR-SU on Phoenix")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dmub/src/Makefile | 2 +-
+ .../drm/amd/display/dmub/src/dmub_dcn314.c | 62 +++++++++++++++++++
+ .../drm/amd/display/dmub/src/dmub_dcn314.h | 33 ++++++++++
+ .../gpu/drm/amd/display/dmub/src/dmub_srv.c | 5 +-
+ 4 files changed, 100 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c
+ create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h
+
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/Makefile b/drivers/gpu/drm/amd/display/dmub/src/Makefile
+index 0589ad4778eea..caf095aca8f3f 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/Makefile
++++ b/drivers/gpu/drm/amd/display/dmub/src/Makefile
+@@ -22,7 +22,7 @@
+
+ DMUB = dmub_srv.o dmub_srv_stat.o dmub_reg.o dmub_dcn20.o dmub_dcn21.o
+ DMUB += dmub_dcn30.o dmub_dcn301.o dmub_dcn302.o dmub_dcn303.o
+-DMUB += dmub_dcn31.o dmub_dcn315.o dmub_dcn316.o
++DMUB += dmub_dcn31.o dmub_dcn314.o dmub_dcn315.o dmub_dcn316.o
+ DMUB += dmub_dcn32.o
+
+ AMD_DAL_DMUB = $(addprefix $(AMDDALPATH)/dmub/src/,$(DMUB))
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c
+new file mode 100644
+index 0000000000000..48a06dbd9be78
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright 2021 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#include "../dmub_srv.h"
++#include "dmub_reg.h"
++#include "dmub_dcn314.h"
++
++#include "dcn/dcn_3_1_4_offset.h"
++#include "dcn/dcn_3_1_4_sh_mask.h"
++
++#define DCN_BASE__INST0_SEG0 0x00000012
++#define DCN_BASE__INST0_SEG1 0x000000C0
++#define DCN_BASE__INST0_SEG2 0x000034C0
++#define DCN_BASE__INST0_SEG3 0x00009000
++#define DCN_BASE__INST0_SEG4 0x02403C00
++#define DCN_BASE__INST0_SEG5 0
++
++#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg
++#define CTX dmub
++#define REGS dmub->regs_dcn31
++#define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
++
++/* Registers. */
++
++const struct dmub_srv_dcn31_regs dmub_srv_dcn314_regs = {
++#define DMUB_SR(reg) REG_OFFSET_EXP(reg),
++ {
++ DMUB_DCN31_REGS()
++ DMCUB_INTERNAL_REGS()
++ },
++#undef DMUB_SR
++
++#define DMUB_SF(reg, field) FD_MASK(reg, field),
++ { DMUB_DCN31_FIELDS() },
++#undef DMUB_SF
++
++#define DMUB_SF(reg, field) FD_SHIFT(reg, field),
++ { DMUB_DCN31_FIELDS() },
++#undef DMUB_SF
++};
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h
+new file mode 100644
+index 0000000000000..674267a2940e9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn314.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright 2021 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef _DMUB_DCN314_H_
++#define _DMUB_DCN314_H_
++
++#include "dmub_dcn31.h"
++
++extern const struct dmub_srv_dcn31_regs dmub_srv_dcn314_regs;
++
++#endif /* _DMUB_DCN314_H_ */
+diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+index 92c18bfb98b3b..6d76ce327d69f 100644
+--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+@@ -32,6 +32,7 @@
+ #include "dmub_dcn302.h"
+ #include "dmub_dcn303.h"
+ #include "dmub_dcn31.h"
++#include "dmub_dcn314.h"
+ #include "dmub_dcn315.h"
+ #include "dmub_dcn316.h"
+ #include "dmub_dcn32.h"
+@@ -226,7 +227,9 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
+ case DMUB_ASIC_DCN314:
+ case DMUB_ASIC_DCN315:
+ case DMUB_ASIC_DCN316:
+- if (asic == DMUB_ASIC_DCN315)
++ if (asic == DMUB_ASIC_DCN314)
++ dmub->regs_dcn31 = &dmub_srv_dcn314_regs;
++ else if (asic == DMUB_ASIC_DCN315)
+ dmub->regs_dcn31 = &dmub_srv_dcn315_regs;
+ else if (asic == DMUB_ASIC_DCN316)
+ dmub->regs_dcn31 = &dmub_srv_dcn316_regs;
+--
+2.39.2
+
--- /dev/null
+From 336d550d35fe70478fd24fc3ab832cd86ef373a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Apr 2023 17:03:06 -0400
+Subject: drm/amd/display: update extended blank for dcn314 onwards
+
+From: Gabe Teeger <gabe.teeger@amd.com>
+
+[ Upstream commit 469a62938a45ef382c9cb7b9fec6c6c1fcd781c0 ]
+
+[Why]
+Flickering and underflow was observed when testing extended
+blank on dcn314.
+
+[What]
+Vstartup is contrainted by vblank_nom, so adjusting it to include
+non-adjusted vtotal in its calculation during freesync video
+means that Vstartup is not changed when vtotal changes.
+This fixed the flickering + underflow.
+
+dc_extended_blank_supported function was removed
+because extended blank is only relevant to when
+zstate is supported. The increased vtotal during
+freesync can be passed to dml regardless of whether
+extended blank is supported or not, so this function is
+not needed.
+
+Updates were made recently in dml to the calculation of
+min_dst_y_next_start. Dml input for dcn314 will now
+always use the newer calculation for min_dst_y_next_start.
+Dml input for older dcn versions remains untouched.
+
+The variable optimized_min_dst_y_next_start
+is replaced everywhere with min_dst_y_next_start,
+and the updated dml allows min_dst_y_next_start to
+increase to an optimized value during freesync video,
+then return to default when freesync is disengaged.
+
+Also removed registry key for controlling
+extended blank feature.
+
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
+Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Signed-off-by: Gabe Teeger <gabe.teeger@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: 2a9482e55968 ("drm/amd/display: Prevent vtotal from being set to 0")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 21 -----------------
+ drivers/gpu/drm/amd/display/dc/dc.h | 2 --
+ .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 4 ++--
+ .../drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 23 +++++++++----------
+ .../dc/dml/dcn31/display_rq_dlg_calc_31.c | 3 +--
+ .../amd/display/dc/dml/dcn314/dcn314_fpu.c | 14 +++++++----
+ .../dc/dml/dcn314/display_rq_dlg_calc_314.c | 16 ++++---------
+ .../amd/display/dc/dml/display_mode_structs.h | 3 +--
+ 8 files changed, 29 insertions(+), 57 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 7f6bdad57c920..d22095a3a265a 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -2632,9 +2632,6 @@ static enum surface_update_type check_update_surfaces_for_stream(
+ stream_update->vrr_active_variable))
+ su_flags->bits.fams_changed = 1;
+
+- if (stream_update->crtc_timing_adjust && dc_extended_blank_supported(dc))
+- su_flags->bits.crtc_timing_adjust = 1;
+-
+ if (su_flags->raw != 0)
+ overall_type = UPDATE_TYPE_FULL;
+
+@@ -4900,21 +4897,3 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo
+ if (pipe->stream_res.abm && pipe->stream_res.abm->funcs->set_abm_pause)
+ pipe->stream_res.abm->funcs->set_abm_pause(pipe->stream_res.abm, !enable, i, pipe->stream_res.tg->inst);
+ }
+-
+-/**
+- * dc_extended_blank_supported - Decide whether extended blank is supported
+- *
+- * @dc: [in] Current DC state
+- *
+- * Extended blank is a freesync optimization feature to be enabled in the
+- * future. During the extra vblank period gained from freesync, we have the
+- * ability to enter z9/z10.
+- *
+- * Return:
+- * Indicate whether extended blank is supported (%true or %false)
+- */
+-bool dc_extended_blank_supported(struct dc *dc)
+-{
+- return dc->debug.extended_blank_optimization && !dc->debug.disable_z10
+- && dc->caps.zstate_support && dc->caps.is_apu;
+-}
+diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
+index 07d86b961c798..9279990e43694 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc.h
++++ b/drivers/gpu/drm/amd/display/dc/dc.h
+@@ -2125,8 +2125,6 @@ struct dc_sink_init_data {
+ bool converter_disable_audio;
+ };
+
+-bool dc_extended_blank_supported(struct dc *dc);
+-
+ struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params);
+
+ /* Newer interfaces */
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+index c38be3c6c234e..a621b6a27c1fc 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+@@ -2128,7 +2128,7 @@ void dcn20_optimize_bandwidth(
+ dc->clk_mgr,
+ context,
+ true);
+- if (dc_extended_blank_supported(dc) && context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) {
++ if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) {
+ for (i = 0; i < dc->res_pool->pipe_count; ++i) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+@@ -2136,7 +2136,7 @@ void dcn20_optimize_bandwidth(
+ && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max
+ && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)
+ pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,
+- pipe_ctx->dlg_regs.optimized_min_dst_y_next_start);
++ pipe_ctx->dlg_regs.min_dst_y_next_start);
+ }
+ }
+ }
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
+index f1c1a4b5fcac3..7661f8946aa31 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
+@@ -948,10 +948,10 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
+ {
+ int plane_count;
+ int i;
+- unsigned int optimized_min_dst_y_next_start_us;
++ unsigned int min_dst_y_next_start_us;
+
+ plane_count = 0;
+- optimized_min_dst_y_next_start_us = 0;
++ min_dst_y_next_start_us = 0;
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ if (context->res_ctx.pipe_ctx[i].plane_state)
+ plane_count++;
+@@ -973,19 +973,18 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
+ else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) {
+ struct dc_link *link = context->streams[0]->sink->link;
+ struct dc_stream_status *stream_status = &context->stream_status[0];
++ struct dc_stream_state *current_stream = context->streams[0];
+ int minmum_z8_residency = dc->debug.minimum_z8_residency_time > 0 ? dc->debug.minimum_z8_residency_time : 1000;
+ bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > (double)minmum_z8_residency;
+ bool is_pwrseq0 = link->link_index == 0;
++ bool isFreesyncVideo;
+
+- if (dc_extended_blank_supported(dc)) {
+- for (i = 0; i < dc->res_pool->pipe_count; i++) {
+- if (context->res_ctx.pipe_ctx[i].stream == context->streams[0]
+- && context->res_ctx.pipe_ctx[i].stream->adjust.v_total_min == context->res_ctx.pipe_ctx[i].stream->adjust.v_total_max
+- && context->res_ctx.pipe_ctx[i].stream->adjust.v_total_min > context->res_ctx.pipe_ctx[i].stream->timing.v_total) {
+- optimized_min_dst_y_next_start_us =
+- context->res_ctx.pipe_ctx[i].dlg_regs.optimized_min_dst_y_next_start_us;
+- break;
+- }
++ isFreesyncVideo = current_stream->adjust.v_total_min == current_stream->adjust.v_total_max;
++ isFreesyncVideo = isFreesyncVideo && current_stream->timing.v_total < current_stream->adjust.v_total_min;
++ for (i = 0; i < dc->res_pool->pipe_count; i++) {
++ if (context->res_ctx.pipe_ctx[i].stream == current_stream && isFreesyncVideo) {
++ min_dst_y_next_start_us = context->res_ctx.pipe_ctx[i].dlg_regs.min_dst_y_next_start_us;
++ break;
+ }
+ }
+
+@@ -993,7 +992,7 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
+ if (stream_status->plane_count > 1)
+ return DCN_ZSTATE_SUPPORT_DISALLOW;
+
+- if (is_pwrseq0 && (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || optimized_min_dst_y_next_start_us > 5000))
++ if (is_pwrseq0 && (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || min_dst_y_next_start_us > 5000))
+ return DCN_ZSTATE_SUPPORT_ALLOW;
+ else if (is_pwrseq0 && link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr)
+ return allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY : DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY;
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
+index 2244e4fb8c96d..fcde8f21b8be0 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
+@@ -987,8 +987,7 @@ static void dml_rq_dlg_get_dlg_params(
+
+ dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start;
+ disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start) * dml_pow(2, 2));
+- disp_dlg_regs->optimized_min_dst_y_next_start_us = 0;
+- disp_dlg_regs->optimized_min_dst_y_next_start = disp_dlg_regs->min_dst_y_next_start;
++ disp_dlg_regs->min_dst_y_next_start_us = 0;
+ ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int)dml_pow(2, 18));
+
+ dml_print("DML_DLG: %s: min_ttu_vblank (us) = %3.2f\n", __func__, min_ttu_vblank);
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+index 9e54e3d0eb780..1d00eb9e73c62 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+@@ -286,6 +286,7 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
+ struct resource_context *res_ctx = &context->res_ctx;
+ struct pipe_ctx *pipe;
+ bool upscaled = false;
++ bool isFreesyncVideo = false;
+
+ dc_assert_fp_enabled();
+
+@@ -299,9 +300,16 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
+ pipe = &res_ctx->pipe_ctx[i];
+ timing = &pipe->stream->timing;
+
+- if (dc_extended_blank_supported(dc) && pipe->stream->adjust.v_total_max == pipe->stream->adjust.v_total_min
+- && pipe->stream->adjust.v_total_min > timing->v_total)
++ isFreesyncVideo = pipe->stream->adjust.v_total_max == pipe->stream->adjust.v_total_min;
++ isFreesyncVideo = isFreesyncVideo && pipe->stream->adjust.v_total_min > timing->v_total;
++
++ if (!isFreesyncVideo) {
++ pipes[pipe_cnt].pipe.dest.vblank_nom =
++ dcn3_14_ip.VBlankNomDefaultUS / (timing->h_total / (timing->pix_clk_100hz / 10000.0));
++ } else {
+ pipes[pipe_cnt].pipe.dest.vtotal = pipe->stream->adjust.v_total_min;
++ pipes[pipe_cnt].pipe.dest.vblank_nom = timing->v_total - pipes[pipe_cnt].pipe.dest.vactive;
++ }
+
+ if (pipe->plane_state &&
+ (pipe->plane_state->src_rect.height < pipe->plane_state->dst_rect.height ||
+@@ -323,8 +331,6 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
+ pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
+- pipes[pipe_cnt].pipe.dest.vblank_nom =
+- dcn3_14_ip.VBlankNomDefaultUS / (timing->h_total / (timing->pix_clk_100hz / 10000.0));
+ pipes[pipe_cnt].pipe.src.dcc_rate = 3;
+ pipes[pipe_cnt].dout.dsc_input_bpc = 0;
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c
+index ea4eb66066c42..4f945458b2b7e 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c
+@@ -1051,7 +1051,6 @@ static void dml_rq_dlg_get_dlg_params(
+
+ float vba__refcyc_per_req_delivery_pre_l = get_refcyc_per_req_delivery_pre_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA
+ float vba__refcyc_per_req_delivery_l = get_refcyc_per_req_delivery_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA
+- int blank_lines = 0;
+
+ memset(disp_dlg_regs, 0, sizeof(*disp_dlg_regs));
+ memset(disp_ttu_regs, 0, sizeof(*disp_ttu_regs));
+@@ -1075,17 +1074,10 @@ static void dml_rq_dlg_get_dlg_params(
+ min_ttu_vblank = get_min_ttu_vblank_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); // From VBA
+
+ dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start;
+- disp_dlg_regs->optimized_min_dst_y_next_start = disp_dlg_regs->min_dst_y_next_start;
+- disp_dlg_regs->optimized_min_dst_y_next_start_us = 0;
+- disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start) * dml_pow(2, 2));
+- blank_lines = (dst->vblank_end + dst->vtotal_min - dst->vblank_start - dst->vstartup_start - 1);
+- if (blank_lines < 0)
+- blank_lines = 0;
+- if (blank_lines != 0) {
+- disp_dlg_regs->optimized_min_dst_y_next_start = vba__min_dst_y_next_start;
+- disp_dlg_regs->optimized_min_dst_y_next_start_us = (disp_dlg_regs->optimized_min_dst_y_next_start * dst->hactive) / (unsigned int) dst->pixel_rate_mhz;
+- disp_dlg_regs->min_dst_y_next_start = disp_dlg_regs->optimized_min_dst_y_next_start;
+- }
++ disp_dlg_regs->min_dst_y_next_start_us =
++ (vba__min_dst_y_next_start * dst->hactive) / (unsigned int) dst->pixel_rate_mhz;
++ disp_dlg_regs->min_dst_y_next_start = vba__min_dst_y_next_start * dml_pow(2, 2);
++
+ ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int)dml_pow(2, 18));
+
+ dml_print("DML_DLG: %s: min_ttu_vblank (us) = %3.2f\n", __func__, min_ttu_vblank);
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
+index 3c077164f3620..ff0246a9458fd 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
++++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
+@@ -619,8 +619,7 @@ struct _vcs_dpi_display_dlg_regs_st {
+ unsigned int refcyc_h_blank_end;
+ unsigned int dlg_vblank_end;
+ unsigned int min_dst_y_next_start;
+- unsigned int optimized_min_dst_y_next_start;
+- unsigned int optimized_min_dst_y_next_start_us;
++ unsigned int min_dst_y_next_start_us;
+ unsigned int refcyc_per_htotal;
+ unsigned int refcyc_x_after_scaler;
+ unsigned int dst_y_after_scaler;
+--
+2.39.2
+
--- /dev/null
+From 1edad98d8fdf0a11e6277f1fc9a3911e0f534d20 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Jul 2023 11:25:00 +0200
+Subject: drm/ttm: never consider pinned BOs for eviction&swap
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+[ Upstream commit a2848d08742c8e8494675892c02c0d22acbe3cf8 ]
+
+There is a small window where we have already incremented the pin count
+but not yet moved the bo from the lru to the pinned list.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Reported-by: Pelloux-Prayer, Pierre-Eric <Pierre-eric.Pelloux-prayer@amd.com>
+Tested-by: Pelloux-Prayer, Pierre-Eric <Pierre-eric.Pelloux-prayer@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Link: https://patchwork.freedesktop.org/patch/msgid/20230707120826.3701-1-christian.koenig@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index 1a1cfd675cc46..7139a522b2f3b 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -517,6 +517,12 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
+ {
+ bool ret = false;
+
++ if (bo->pin_count) {
++ *locked = false;
++ *busy = false;
++ return false;
++ }
++
+ if (bo->base.resv == ctx->resv) {
+ dma_resv_assert_held(bo->base.resv);
+ if (ctx->allow_res_evict)
+--
+2.39.2
+
--- /dev/null
+From db8ba03ed7a92f00d8af314cfde63d1439b305e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 3 Jun 2023 23:03:13 +0800
+Subject: ext4: add EXT4_MB_HINT_GOAL_ONLY test in ext4_mb_use_preallocated
+
+From: Kemeng Shi <shikemeng@huaweicloud.com>
+
+[ Upstream commit 1eff590489a213a213c57d96b86f48b32cdf8c3a ]
+
+ext4_mb_use_preallocated will ignore the demand to alloc goal blocks,
+although the EXT4_MB_HINT_GOAL_ONLY is requested.
+For group pa, ext4_mb_group_or_file will not set EXT4_MB_HINT_GROUP_ALLOC
+if EXT4_MB_HINT_GOAL_ONLY is set. So we will not alloc goal blocks from
+group pa if EXT4_MB_HINT_GOAL_ONLY is set.
+For inode pa, ext4_mb_pa_goal_check is added to check if free extent in
+found inode pa meets goal blocks when EXT4_MB_HINT_GOAL_ONLY is set.
+
+Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
+Suggested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Link: https://lore.kernel.org/r/20230603150327.3596033-6-shikemeng@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 9d3de7ee192a ("ext4: fix rbtree traversal bug in ext4_mb_use_preallocated")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 34 +++++++++++++++++++++++++++++++++-
+ 1 file changed, 33 insertions(+), 1 deletion(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index fd4d12c58c3b4..1f4d00a4308dc 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -4528,6 +4528,37 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
+ return pa;
+ }
+
++/*
++ * check if found pa meets EXT4_MB_HINT_GOAL_ONLY
++ */
++static bool
++ext4_mb_pa_goal_check(struct ext4_allocation_context *ac,
++ struct ext4_prealloc_space *pa)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
++ ext4_fsblk_t start;
++
++ if (likely(!(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)))
++ return true;
++
++ /*
++ * If EXT4_MB_HINT_GOAL_ONLY is set, ac_g_ex will not be adjusted
++ * in ext4_mb_normalize_request and will keep same with ac_o_ex
++ * from ext4_mb_initialize_context. Choose ac_g_ex here to keep
++ * consistent with ext4_mb_find_by_goal.
++ */
++ start = pa->pa_pstart +
++ (ac->ac_g_ex.fe_logical - pa->pa_lstart);
++ if (ext4_grp_offs_to_block(ac->ac_sb, &ac->ac_g_ex) != start)
++ return false;
++
++ if (ac->ac_g_ex.fe_len > pa->pa_len -
++ EXT4_B2C(sbi, ac->ac_g_ex.fe_logical - pa->pa_lstart))
++ return false;
++
++ return true;
++}
++
+ /*
+ * search goal blocks in preallocated space
+ */
+@@ -4578,7 +4609,8 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
+
+ /* found preallocated blocks, use them */
+ spin_lock(&tmp_pa->pa_lock);
+- if (tmp_pa->pa_deleted == 0 && tmp_pa->pa_free) {
++ if (tmp_pa->pa_deleted == 0 && tmp_pa->pa_free &&
++ likely(ext4_mb_pa_goal_check(ac, tmp_pa))) {
+ atomic_inc(&tmp_pa->pa_count);
+ ext4_mb_use_inode_pa(ac, tmp_pa);
+ spin_unlock(&tmp_pa->pa_lock);
+--
+2.39.2
+
--- /dev/null
+From 2beb40ba0b2115dd39bfc0a9527cb1eca953c82d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Jul 2023 22:45:24 +0530
+Subject: ext4: fix rbtree traversal bug in ext4_mb_use_preallocated
+
+From: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+
+[ Upstream commit 9d3de7ee192a6a253f475197fe4d2e2af10a731f ]
+
+During allocations, while looking for preallocations(PA) in the per
+inode rbtree, we can't do a direct traversal of the tree because
+ext4_mb_discard_group_preallocation() can paralelly mark the pa deleted
+and that can cause direct traversal to skip some entries. This was
+leading to a BUG_ON() being hit [1] when we missed a PA that could satisfy
+our request and ultimately tried to create a new PA that would overlap
+with the missed one.
+
+To makes sure we handle that case while still keeping the performance of
+the rbtree, we make use of the fact that the only pa that could possibly
+overlap the original goal start is the one that satisfies the below
+conditions:
+
+ 1. It must have it's logical start immediately to the left of
+ (ie less than) original logical start.
+
+ 2. It must not be deleted
+
+To find this pa we use the following traversal method:
+
+1. Descend into the rbtree normally to find the immediate neighboring
+PA. Here we keep descending irrespective of if the PA is deleted or if
+it overlaps with our request etc. The goal is to find an immediately
+adjacent PA.
+
+2. If the found PA is on right of original goal, use rb_prev() to find
+the left adjacent PA.
+
+3. Check if this PA is deleted and keep moving left with rb_prev() until
+a non deleted PA is found.
+
+4. This is the PA we are looking for. Now we can check if it can satisfy
+the original request and proceed accordingly.
+
+This approach also takes care of having deleted PAs in the tree.
+
+(While we are at it, also fix a possible overflow bug in calculating the
+end of a PA)
+
+[1] https://lore.kernel.org/linux-ext4/CA+G9fYv2FRpLqBZf34ZinR8bU2_ZRAUOjKAD3+tKRFaEQHtt8Q@mail.gmail.com/
+
+Cc: stable@kernel.org # 6.4
+Fixes: 3872778664e3 ("ext4: Use rbtrees to manage PAs instead of inode i_prealloc_list")
+Signed-off-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org>
+Reviewed-by: Ritesh Harjani (IBM) ritesh.list@gmail.com
+Tested-by: Ritesh Harjani (IBM) ritesh.list@gmail.com
+Link: https://lore.kernel.org/r/edd2efda6a83e6343c5ace9deea44813e71dbe20.1690045963.git.ojaswin@linux.ibm.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 158 ++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 131 insertions(+), 27 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index d49d1a7af22db..3fa5de892d89d 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -4569,8 +4569,8 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
+ int order, i;
+ struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
+ struct ext4_locality_group *lg;
+- struct ext4_prealloc_space *tmp_pa, *cpa = NULL;
+- ext4_lblk_t tmp_pa_start, tmp_pa_end;
++ struct ext4_prealloc_space *tmp_pa = NULL, *cpa = NULL;
++ loff_t tmp_pa_end;
+ struct rb_node *iter;
+ ext4_fsblk_t goal_block;
+
+@@ -4578,47 +4578,151 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
+ if (!(ac->ac_flags & EXT4_MB_HINT_DATA))
+ return false;
+
+- /* first, try per-file preallocation */
++ /*
++ * first, try per-file preallocation by searching the inode pa rbtree.
++ *
++ * Here, we can't do a direct traversal of the tree because
++ * ext4_mb_discard_group_preallocation() can paralelly mark the pa
++ * deleted and that can cause direct traversal to skip some entries.
++ */
+ read_lock(&ei->i_prealloc_lock);
++
++ if (RB_EMPTY_ROOT(&ei->i_prealloc_node)) {
++ goto try_group_pa;
++ }
++
++ /*
++ * Step 1: Find a pa with logical start immediately adjacent to the
++ * original logical start. This could be on the left or right.
++ *
++ * (tmp_pa->pa_lstart never changes so we can skip locking for it).
++ */
+ for (iter = ei->i_prealloc_node.rb_node; iter;
+ iter = ext4_mb_pa_rb_next_iter(ac->ac_o_ex.fe_logical,
+- tmp_pa_start, iter)) {
++ tmp_pa->pa_lstart, iter)) {
+ tmp_pa = rb_entry(iter, struct ext4_prealloc_space,
+ pa_node.inode_node);
++ }
+
+- /* all fields in this condition don't change,
+- * so we can skip locking for them */
+- tmp_pa_start = tmp_pa->pa_lstart;
+- tmp_pa_end = tmp_pa->pa_lstart + EXT4_C2B(sbi, tmp_pa->pa_len);
+-
+- /* original request start doesn't lie in this PA */
+- if (ac->ac_o_ex.fe_logical < tmp_pa_start ||
+- ac->ac_o_ex.fe_logical >= tmp_pa_end)
+- continue;
++ /*
++ * Step 2: The adjacent pa might be to the right of logical start, find
++ * the left adjacent pa. After this step we'd have a valid tmp_pa whose
++ * logical start is towards the left of original request's logical start
++ */
++ if (tmp_pa->pa_lstart > ac->ac_o_ex.fe_logical) {
++ struct rb_node *tmp;
++ tmp = rb_prev(&tmp_pa->pa_node.inode_node);
+
+- /* non-extent files can't have physical blocks past 2^32 */
+- if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)) &&
+- (tmp_pa->pa_pstart + EXT4_C2B(sbi, tmp_pa->pa_len) >
+- EXT4_MAX_BLOCK_FILE_PHYS)) {
++ if (tmp) {
++ tmp_pa = rb_entry(tmp, struct ext4_prealloc_space,
++ pa_node.inode_node);
++ } else {
+ /*
+- * Since PAs don't overlap, we won't find any
+- * other PA to satisfy this.
++ * If there is no adjacent pa to the left then finding
++ * an overlapping pa is not possible hence stop searching
++ * inode pa tree
+ */
+- break;
++ goto try_group_pa;
+ }
++ }
+
+- /* found preallocated blocks, use them */
++ BUG_ON(!(tmp_pa && tmp_pa->pa_lstart <= ac->ac_o_ex.fe_logical));
++
++ /*
++ * Step 3: If the left adjacent pa is deleted, keep moving left to find
++ * the first non deleted adjacent pa. After this step we should have a
++ * valid tmp_pa which is guaranteed to be non deleted.
++ */
++ for (iter = &tmp_pa->pa_node.inode_node;; iter = rb_prev(iter)) {
++ if (!iter) {
++ /*
++ * no non deleted left adjacent pa, so stop searching
++ * inode pa tree
++ */
++ goto try_group_pa;
++ }
++ tmp_pa = rb_entry(iter, struct ext4_prealloc_space,
++ pa_node.inode_node);
+ spin_lock(&tmp_pa->pa_lock);
+- if (tmp_pa->pa_deleted == 0 && tmp_pa->pa_free &&
+- likely(ext4_mb_pa_goal_check(ac, tmp_pa))) {
+- atomic_inc(&tmp_pa->pa_count);
+- ext4_mb_use_inode_pa(ac, tmp_pa);
++ if (tmp_pa->pa_deleted == 0) {
++ /*
++ * We will keep holding the pa_lock from
++ * this point on because we don't want group discard
++ * to delete this pa underneath us. Since group
++ * discard is anyways an ENOSPC operation it
++ * should be okay for it to wait a few more cycles.
++ */
++ break;
++ } else {
+ spin_unlock(&tmp_pa->pa_lock);
+- read_unlock(&ei->i_prealloc_lock);
+- return true;
+ }
++ }
++
++ BUG_ON(!(tmp_pa && tmp_pa->pa_lstart <= ac->ac_o_ex.fe_logical));
++ BUG_ON(tmp_pa->pa_deleted == 1);
++
++ /*
++ * Step 4: We now have the non deleted left adjacent pa. Only this
++ * pa can possibly satisfy the request hence check if it overlaps
++ * original logical start and stop searching if it doesn't.
++ */
++ tmp_pa_end = (loff_t)tmp_pa->pa_lstart + EXT4_C2B(sbi, tmp_pa->pa_len);
++
++ if (ac->ac_o_ex.fe_logical >= tmp_pa_end) {
++ spin_unlock(&tmp_pa->pa_lock);
++ goto try_group_pa;
++ }
++
++ /* non-extent files can't have physical blocks past 2^32 */
++ if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)) &&
++ (tmp_pa->pa_pstart + EXT4_C2B(sbi, tmp_pa->pa_len) >
++ EXT4_MAX_BLOCK_FILE_PHYS)) {
++ /*
++ * Since PAs don't overlap, we won't find any other PA to
++ * satisfy this.
++ */
+ spin_unlock(&tmp_pa->pa_lock);
++ goto try_group_pa;
++ }
++
++ if (tmp_pa->pa_free && likely(ext4_mb_pa_goal_check(ac, tmp_pa))) {
++ atomic_inc(&tmp_pa->pa_count);
++ ext4_mb_use_inode_pa(ac, tmp_pa);
++ spin_unlock(&tmp_pa->pa_lock);
++ read_unlock(&ei->i_prealloc_lock);
++ return true;
++ } else {
++ /*
++ * We found a valid overlapping pa but couldn't use it because
++ * it had no free blocks. This should ideally never happen
++ * because:
++ *
++ * 1. When a new inode pa is added to rbtree it must have
++ * pa_free > 0 since otherwise we won't actually need
++ * preallocation.
++ *
++ * 2. An inode pa that is in the rbtree can only have it's
++ * pa_free become zero when another thread calls:
++ * ext4_mb_new_blocks
++ * ext4_mb_use_preallocated
++ * ext4_mb_use_inode_pa
++ *
++ * 3. Further, after the above calls make pa_free == 0, we will
++ * immediately remove it from the rbtree in:
++ * ext4_mb_new_blocks
++ * ext4_mb_release_context
++ * ext4_mb_put_pa
++ *
++ * 4. Since the pa_free becoming 0 and pa_free getting removed
++ * from tree both happen in ext4_mb_new_blocks, which is always
++ * called with i_data_sem held for data allocations, we can be
++ * sure that another process will never see a pa in rbtree with
++ * pa_free == 0.
++ */
++ WARN_ON_ONCE(tmp_pa->pa_free == 0);
+ }
++ spin_unlock(&tmp_pa->pa_lock);
++try_group_pa:
+ read_unlock(&ei->i_prealloc_lock);
+
+ /* can we use group allocation? */
+--
+2.39.2
+
--- /dev/null
+From 4af2668d4db0d9d410747a409be865c0abbaba04 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 May 2023 18:03:40 +0530
+Subject: ext4: mballoc: Remove useless setting of ac_criteria
+
+From: Ritesh Harjani <ritesh.list@gmail.com>
+
+[ Upstream commit 569f196f1e7a14472f21734170411f75a3179db0 ]
+
+There will be changes coming in future patches which will introduce a new
+criteria for block allocation. This removes the useless setting of ac_criteria.
+AFAIU, this might be only used to differentiate between whether a preallocated
+blocks was allocated or was regular allocator called for allocating blocks.
+Hence this also adds the debug prints to identify what type of block allocation
+was done in ext4_mb_show_ac().
+
+Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Signed-off-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/1dbae05617519cb6202f1b299c9d1be3e7cda763.1685449706.git.ojaswin@linux.ibm.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 9d3de7ee192a ("ext4: fix rbtree traversal bug in ext4_mb_use_preallocated")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index 1f4d00a4308dc..d49d1a7af22db 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -4614,7 +4614,6 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
+ atomic_inc(&tmp_pa->pa_count);
+ ext4_mb_use_inode_pa(ac, tmp_pa);
+ spin_unlock(&tmp_pa->pa_lock);
+- ac->ac_criteria = 10;
+ read_unlock(&ei->i_prealloc_lock);
+ return true;
+ }
+@@ -4657,7 +4656,6 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
+ }
+ if (cpa) {
+ ext4_mb_use_group_pa(ac, cpa);
+- ac->ac_criteria = 20;
+ return true;
+ }
+ return false;
+@@ -5431,6 +5429,10 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
+ (unsigned long)ac->ac_b_ex.fe_logical,
+ (int)ac->ac_criteria);
+ mb_debug(sb, "%u found", ac->ac_found);
++ mb_debug(sb, "used pa: %s, ", ac->ac_pa ? "yes" : "no");
++ if (ac->ac_pa)
++ mb_debug(sb, "pa_type %s\n", ac->ac_pa->pa_type == MB_GROUP_PA ?
++ "group pa" : "inode pa");
+ ext4_mb_show_pa(sb);
+ }
+ #else
+--
+2.39.2
+
--- /dev/null
+From 95fab901a4309cbd2922959c6b7c9ac774f085c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Jul 2023 13:41:01 +0200
+Subject: gpio: mvebu: fix irq domain leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit 644ee70267a934be27370f9aa618b29af7290544 ]
+
+Uwe Kleine-König pointed out we still have one resource leak in the mvebu
+driver triggered on driver detach. Let's address it with a custom devm
+action.
+
+Fixes: 812d47889a8e ("gpio/mvebu: Use irq_domain_add_linear")
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-mvebu.c | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index a35958e7adf60..67497116ce27d 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -1112,6 +1112,13 @@ static int mvebu_gpio_probe_syscon(struct platform_device *pdev,
+ return 0;
+ }
+
++static void mvebu_gpio_remove_irq_domain(void *data)
++{
++ struct irq_domain *domain = data;
++
++ irq_domain_remove(domain);
++}
++
+ static int mvebu_gpio_probe(struct platform_device *pdev)
+ {
+ struct mvebu_gpio_chip *mvchip;
+@@ -1246,13 +1253,18 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ err = devm_add_action_or_reset(&pdev->dev, mvebu_gpio_remove_irq_domain,
++ mvchip->domain);
++ if (err)
++ return err;
++
+ err = irq_alloc_domain_generic_chips(
+ mvchip->domain, ngpios, 2, np->name, handle_level_irq,
+ IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
+ if (err) {
+ dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
+ mvchip->chip.label);
+- goto err_domain;
++ return err;
+ }
+
+ /*
+@@ -1292,10 +1304,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+ }
+
+ return 0;
+-
+-err_domain:
+- irq_domain_remove(mvchip->domain);
+- return err;
+ }
+
+ static struct platform_driver mvebu_gpio_driver = {
+--
+2.39.2
+
--- /dev/null
+From 1c433ec570b95263cea824d2b2b1b3ea601cf5c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Jul 2023 16:27:43 +0200
+Subject: gpio: mvebu: Make use of devm_pwmchip_add
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 1945063eb59e64d2919cb14d54d081476d9e53bb ]
+
+This allows to get rid of a call to pwmchip_remove() in the error path. There
+is no .remove function for this driver, so this change fixes a resource leak
+when a gpio-mvebu device is unbound.
+
+Fixes: 757642f9a584 ("gpio: mvebu: Add limited PWM support")
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Andy Shevchenko <andy@kernel.org>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-mvebu.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index a68f682aec012..a35958e7adf60 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -874,7 +874,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
+
+ spin_lock_init(&mvpwm->lock);
+
+- return pwmchip_add(&mvpwm->chip);
++ return devm_pwmchip_add(dev, &mvpwm->chip);
+ }
+
+ #ifdef CONFIG_DEBUG_FS
+@@ -1243,8 +1243,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+ if (!mvchip->domain) {
+ dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
+ mvchip->chip.label);
+- err = -ENODEV;
+- goto err_pwm;
++ return -ENODEV;
+ }
+
+ err = irq_alloc_domain_generic_chips(
+@@ -1296,9 +1295,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+
+ err_domain:
+ irq_domain_remove(mvchip->domain);
+-err_pwm:
+- pwmchip_remove(&mvchip->mvpwm->chip);
+-
+ return err;
+ }
+
+--
+2.39.2
+
--- /dev/null
+From 08963293aa14a19e19669f93dbfae83758d8ba49 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jul 2023 14:34:25 +0200
+Subject: gpio: tps68470: Make tps68470_gpio_output() always set the initial
+ value
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit 5a7adc6c1069ce31ef4f606ae9c05592c80a6ab5 ]
+
+Make tps68470_gpio_output() call tps68470_gpio_set() for output-only pins
+too, so that the initial value passed to gpiod_direction_output() is
+honored for these pins too.
+
+Fixes: 275b13a65547 ("gpio: Add support for TPS68470 GPIOs")
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
+Tested-by: Daniel Scally <dan.scally@ideasonboard.com>
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-tps68470.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c
+index aaddcabe9b359..532deaddfd4e2 100644
+--- a/drivers/gpio/gpio-tps68470.c
++++ b/drivers/gpio/gpio-tps68470.c
+@@ -91,13 +91,13 @@ static int tps68470_gpio_output(struct gpio_chip *gc, unsigned int offset,
+ struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
+ struct regmap *regmap = tps68470_gpio->tps68470_regmap;
+
++ /* Set the initial value */
++ tps68470_gpio_set(gc, offset, value);
++
+ /* rest are always outputs */
+ if (offset >= TPS68470_N_REGULAR_GPIO)
+ return 0;
+
+- /* Set the initial value */
+- tps68470_gpio_set(gc, offset, value);
+-
+ return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset),
+ TPS68470_GPIO_MODE_MASK,
+ TPS68470_GPIO_MODE_OUT_CMOS);
+--
+2.39.2
+
--- /dev/null
+From 2b98639fc395dfd5c4c4d9cf298938ba75bc9d70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Feb 2018 17:24:57 +0100
+Subject: i2c: Delete error messages for failed memory allocations
+
+From: Markus Elfring <elfring@users.sourceforge.net>
+
+[ Upstream commit 6b3b21a8542fd2fb6ffc61bc13b9419f0c58ebad ]
+
+These issues were detected by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-ibm_iic.c | 4 +---
+ drivers/i2c/busses/i2c-nomadik.c | 1 -
+ drivers/i2c/busses/i2c-sh7760.c | 1 -
+ drivers/i2c/busses/i2c-tiny-usb.c | 4 +---
+ 4 files changed, 2 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
+index eeb80e34f9ad7..de3b609515e08 100644
+--- a/drivers/i2c/busses/i2c-ibm_iic.c
++++ b/drivers/i2c/busses/i2c-ibm_iic.c
+@@ -694,10 +694,8 @@ static int iic_probe(struct platform_device *ofdev)
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (!dev) {
+- dev_err(&ofdev->dev, "failed to allocate device data\n");
++ if (!dev)
+ return -ENOMEM;
+- }
+
+ platform_set_drvdata(ofdev, dev);
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index a2d12a5b1c34c..05eaae5aeb180 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -972,7 +972,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+- dev_err(&adev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
+index 319d1fa617c88..a0ccc5d009874 100644
+--- a/drivers/i2c/busses/i2c-sh7760.c
++++ b/drivers/i2c/busses/i2c-sh7760.c
+@@ -445,7 +445,6 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
+
+ id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
+ if (!id) {
+- dev_err(&pdev->dev, "no mem for private data\n");
+ ret = -ENOMEM;
+ goto out0;
+ }
+diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
+index 7279ca0eaa2d0..d1fa9ff5aeab4 100644
+--- a/drivers/i2c/busses/i2c-tiny-usb.c
++++ b/drivers/i2c/busses/i2c-tiny-usb.c
+@@ -226,10 +226,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (dev == NULL) {
+- dev_err(&interface->dev, "Out of memory\n");
++ if (!dev)
+ goto error;
+- }
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+--
+2.39.2
+
--- /dev/null
+From 9ec5ca0ec46bcd08e53e7ea444474fab286c10ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Feb 2018 14:50:09 +0100
+Subject: i2c: Improve size determinations
+
+From: Markus Elfring <elfring@users.sourceforge.net>
+
+[ Upstream commit 06e989578232da33a7fe96b04191b862af8b2cec ]
+
+Replace the specification of a data structure by a pointer dereference
+as the parameter for the operator "sizeof" to make the corresponding
+size determination a bit safer according to the Linux coding style
+convention.
+
+This issue was detected by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 2 +-
+ drivers/i2c/busses/i2c-sh7760.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 05eaae5aeb180..5004b9dd98563 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -970,7 +970,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+ struct i2c_vendor_data *vendor = id->data;
+ u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+
+- dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
++ dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err_no_mem;
+diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
+index a0ccc5d009874..051b904cb35f6 100644
+--- a/drivers/i2c/busses/i2c-sh7760.c
++++ b/drivers/i2c/busses/i2c-sh7760.c
+@@ -443,7 +443,7 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
+ goto out0;
+ }
+
+- id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
++ id = kzalloc(sizeof(*id), GFP_KERNEL);
+ if (!id) {
+ ret = -ENOMEM;
+ goto out0;
+--
+2.39.2
+
--- /dev/null
+From 61fa202f6095d3b9bff52b8e2c89bcd725c4528b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Jul 2023 21:50:28 +0200
+Subject: i2c: nomadik: Remove a useless call in the remove function
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 05f933d5f7318b03ff2028c1704dc867ac16f2c7 ]
+
+Since commit 235602146ec9 ("i2c-nomadik: turn the platform driver to an amba
+driver"), there is no more request_mem_region() call in this driver.
+
+So remove the release_mem_region() call from the remove function which is
+likely a left over.
+
+Fixes: 235602146ec9 ("i2c-nomadik: turn the platform driver to an amba driver")
+Cc: <stable@vger.kernel.org> # v3.6+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 2141ba05dfece..9c5d66bd6dc1c 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -1040,7 +1040,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ static void nmk_i2c_remove(struct amba_device *adev)
+ {
+- struct resource *res = &adev->res;
+ struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
+
+ i2c_del_adapter(&dev->adap);
+@@ -1049,7 +1048,6 @@ static void nmk_i2c_remove(struct amba_device *adev)
+ clear_all_interrupts(dev);
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+- release_mem_region(res->start, resource_size(res));
+ }
+
+ static struct i2c_vendor_data vendor_stn8815 = {
+--
+2.39.2
+
--- /dev/null
+From d240104ccfcdd4640448f434652fc68f04e6891b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Jun 2023 03:36:59 +0200
+Subject: i2c: nomadik: Remove unnecessary goto label
+
+From: Andi Shyti <andi.shyti@kernel.org>
+
+[ Upstream commit 1c5d33fff0d375e4ab7c4261dc62a286babbb4c6 ]
+
+The err_no_mem goto label doesn't do anything. Remove it.
+
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 21 ++++++++-------------
+ 1 file changed, 8 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 5004b9dd98563..8b9577318388e 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -971,10 +971,9 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+ u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+
+ dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL);
+- if (!dev) {
+- ret = -ENOMEM;
+- goto err_no_mem;
+- }
++ if (!dev)
++ return -ENOMEM;
++
+ dev->vendor = vendor;
+ dev->adev = adev;
+ nmk_i2c_of_probe(np, dev);
+@@ -995,30 +994,27 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
+ resource_size(&adev->res));
+- if (!dev->virtbase) {
+- ret = -ENOMEM;
+- goto err_no_mem;
+- }
++ if (!dev->virtbase)
++ return -ENOMEM;
+
+ dev->irq = adev->irq[0];
+ ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
+ DRIVER_NAME, dev);
+ if (ret) {
+ dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
+- goto err_no_mem;
++ return ret;
+ }
+
+ dev->clk = devm_clk_get(&adev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(&adev->dev, "could not get i2c clock\n");
+- ret = PTR_ERR(dev->clk);
+- goto err_no_mem;
++ return PTR_ERR(dev->clk);
+ }
+
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ dev_err(&adev->dev, "can't prepare_enable clock\n");
+- goto err_no_mem;
++ return ret;
+ }
+
+ init_hw(dev);
+@@ -1049,7 +1045,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ err_no_adap:
+ clk_disable_unprepare(dev->clk);
+- err_no_mem:
+
+ return ret;
+ }
+--
+2.39.2
+
--- /dev/null
+From f1d5017e300e655246659e00c554b9a85bcbc60c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Jun 2023 03:37:00 +0200
+Subject: i2c: nomadik: Use devm_clk_get_enabled()
+
+From: Andi Shyti <andi.shyti@kernel.org>
+
+[ Upstream commit 9c7174db4cdd111e10d19eed5c36fd978a14c8a2 ]
+
+Replace the pair of functions, devm_clk_get() and
+clk_prepare_enable(), with a single function
+devm_clk_get_enabled().
+
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 18 +++---------------
+ 1 file changed, 3 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 8b9577318388e..2141ba05dfece 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -1005,18 +1005,12 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+ return ret;
+ }
+
+- dev->clk = devm_clk_get(&adev->dev, NULL);
++ dev->clk = devm_clk_get_enabled(&adev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+- dev_err(&adev->dev, "could not get i2c clock\n");
++ dev_err(&adev->dev, "could enable i2c clock\n");
+ return PTR_ERR(dev->clk);
+ }
+
+- ret = clk_prepare_enable(dev->clk);
+- if (ret) {
+- dev_err(&adev->dev, "can't prepare_enable clock\n");
+- return ret;
+- }
+-
+ init_hw(dev);
+
+ adap = &dev->adap;
+@@ -1037,16 +1031,11 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+- goto err_no_adap;
++ return ret;
+
+ pm_runtime_put(&adev->dev);
+
+ return 0;
+-
+- err_no_adap:
+- clk_disable_unprepare(dev->clk);
+-
+- return ret;
+ }
+
+ static void nmk_i2c_remove(struct amba_device *adev)
+@@ -1060,7 +1049,6 @@ static void nmk_i2c_remove(struct amba_device *adev)
+ clear_all_interrupts(dev);
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+- clk_disable_unprepare(dev->clk);
+ release_mem_region(res->start, resource_size(res));
+ }
+
+--
+2.39.2
+
--- /dev/null
+From 0b655dfc74389be3f5ae6590b7c3923445076d61 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Jul 2023 13:56:07 +0200
+Subject: io_uring: don't audit the capability check in io_uring_create()
+
+From: Ondrej Mosnacek <omosnace@redhat.com>
+
+[ Upstream commit 6adc2272aaaf84f34b652cf77f770c6fcc4b8336 ]
+
+The check being unconditional may lead to unwanted denials reported by
+LSMs when a process has the capability granted by DAC, but denied by an
+LSM. In the case of SELinux such denials are a problem, since they can't
+be effectively filtered out via the policy and when not silenced, they
+produce noise that may hide a true problem or an attack.
+
+Since not having the capability merely means that the created io_uring
+context will be accounted against the current user's RLIMIT_MEMLOCK
+limit, we can disable auditing of denials for this check by using
+ns_capable_noaudit() instead of capable().
+
+Fixes: 2b188cc1bb85 ("Add io_uring IO interface")
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2193317
+Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
+Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
+Link: https://lore.kernel.org/r/20230718115607.65652-1-omosnace@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index d6667b435dd39..685cf14a7189e 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -3859,7 +3859,7 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
+ ctx->syscall_iopoll = 1;
+
+ ctx->compat = in_compat_syscall();
+- if (!capable(CAP_IPC_LOCK))
++ if (!ns_capable_noaudit(&init_user_ns, CAP_IPC_LOCK))
+ ctx->user = get_uid(current_user());
+
+ /*
+--
+2.39.2
+
--- /dev/null
+From 091939319a56dbd39ddf118c5e9ffa2d348df215 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:27 +0800
+Subject: jbd2: fix a race when checking checkpoint buffer busy
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit 46f881b5b1758dc4a35fba4a643c10717d0cf427 ]
+
+Before removing checkpoint buffer from the t_checkpoint_list, we have to
+check both BH_Dirty and BH_Lock bits together to distinguish buffers
+have not been or were being written back. But __cp_buffer_busy() checks
+them separately, it first check lock state and then check dirty, the
+window between these two checks could be raced by writing back
+procedure, which locks buffer and clears buffer dirty before I/O
+completes. So it cannot guarantee checkpointing buffers been written
+back to disk if some error happens later. Finally, it may clean
+checkpoint transactions and lead to inconsistent filesystem.
+
+jbd2_journal_forget() and __journal_try_to_free_buffer() also have the
+same problem (journal_unmap_buffer() escape from this issue since it's
+running under the buffer lock), so fix them through introducing a new
+helper to try holding the buffer lock and remove really clean buffer.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
+Cc: stable@vger.kernel.org
+Suggested-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-6-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 38 +++++++++++++++++++++++++++++++++++---
+ fs/jbd2/transaction.c | 17 +++++------------
+ include/linux/jbd2.h | 1 +
+ 3 files changed, 41 insertions(+), 15 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index 42b34cab64fbd..9ec91017a7f3c 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -376,11 +376,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+
+- if (!destroy && __cp_buffer_busy(jh))
+- continue;
++ if (destroy) {
++ ret = __jbd2_journal_remove_checkpoint(jh);
++ } else {
++ ret = jbd2_journal_try_remove_checkpoint(jh);
++ if (ret < 0)
++ continue;
++ }
+
+ nr_freed++;
+- ret = __jbd2_journal_remove_checkpoint(jh);
+ if (ret) {
+ *released = true;
+ break;
+@@ -616,6 +620,34 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
+ return 1;
+ }
+
++/*
++ * Check the checkpoint buffer and try to remove it from the checkpoint
++ * list if it's clean. Returns -EBUSY if it is not clean, returns 1 if
++ * it frees the transaction, 0 otherwise.
++ *
++ * This function is called with j_list_lock held.
++ */
++int jbd2_journal_try_remove_checkpoint(struct journal_head *jh)
++{
++ struct buffer_head *bh = jh2bh(jh);
++
++ if (!trylock_buffer(bh))
++ return -EBUSY;
++ if (buffer_dirty(bh)) {
++ unlock_buffer(bh);
++ return -EBUSY;
++ }
++ unlock_buffer(bh);
++
++ /*
++ * Buffer is clean and the IO has finished (we held the buffer
++ * lock) so the checkpoint is done. We can safely remove the
++ * buffer from this transaction.
++ */
++ JBUFFER_TRACE(jh, "remove from checkpoint list");
++ return __jbd2_journal_remove_checkpoint(jh);
++}
++
+ /*
+ * journal_insert_checkpoint: put a committed buffer onto a checkpoint
+ * list so that we know when it is safe to clean the transaction out of
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index 18611241f4513..6ef5022949c46 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -1784,8 +1784,7 @@ int jbd2_journal_forget(handle_t *handle, struct buffer_head *bh)
+ * Otherwise, if the buffer has been written to disk,
+ * it is safe to remove the checkpoint and drop it.
+ */
+- if (!buffer_dirty(bh)) {
+- __jbd2_journal_remove_checkpoint(jh);
++ if (jbd2_journal_try_remove_checkpoint(jh) >= 0) {
+ spin_unlock(&journal->j_list_lock);
+ goto drop;
+ }
+@@ -2112,20 +2111,14 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
+
+ jh = bh2jh(bh);
+
+- if (buffer_locked(bh) || buffer_dirty(bh))
+- goto out;
+-
+ if (jh->b_next_transaction != NULL || jh->b_transaction != NULL)
+- goto out;
++ return;
+
+ spin_lock(&journal->j_list_lock);
+- if (jh->b_cp_transaction != NULL) {
+- /* written-back checkpointed metadata buffer */
+- JBUFFER_TRACE(jh, "remove from checkpoint list");
+- __jbd2_journal_remove_checkpoint(jh);
+- }
++ /* Remove written-back checkpointed metadata buffer */
++ if (jh->b_cp_transaction != NULL)
++ jbd2_journal_try_remove_checkpoint(jh);
+ spin_unlock(&journal->j_list_lock);
+-out:
+ return;
+ }
+
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index 91a2cf4bc5756..c212da35a052c 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -1443,6 +1443,7 @@ extern void jbd2_journal_commit_transaction(journal_t *);
+ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy);
+ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal, unsigned long *nr_to_scan);
+ int __jbd2_journal_remove_checkpoint(struct journal_head *);
++int jbd2_journal_try_remove_checkpoint(struct journal_head *jh);
+ void jbd2_journal_destroy_checkpoint(journal_t *journal);
+ void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
+
+--
+2.39.2
+
--- /dev/null
+From 3f003a96c8117824ae7320b53c5fcad340bd1910 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:26 +0800
+Subject: jbd2: Fix wrongly judgement for buffer head removing while doing
+ checkpoint
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+[ Upstream commit e34c8dd238d0c9368b746480f313055f5bab5040 ]
+
+Following process,
+
+jbd2_journal_commit_transaction
+// there are several dirty buffer heads in transaction->t_checkpoint_list
+ P1 wb_workfn
+jbd2_log_do_checkpoint
+ if (buffer_locked(bh)) // false
+ __block_write_full_page
+ trylock_buffer(bh)
+ test_clear_buffer_dirty(bh)
+ if (!buffer_dirty(bh))
+ __jbd2_journal_remove_checkpoint(jh)
+ if (buffer_write_io_error(bh)) // false
+ >> bh IO error occurs <<
+ jbd2_cleanup_journal_tail
+ __jbd2_update_log_tail
+ jbd2_write_superblock
+ // The bh won't be replayed in next mount.
+, which could corrupt the ext4 image, fetch a reproducer in [Link].
+
+Since writeback process clears buffer dirty after locking buffer head,
+we can fix it by try locking buffer and check dirtiness while buffer is
+locked, the buffer head can be removed if it is neither dirty nor locked.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
+Fixes: 470decc613ab ("[PATCH] jbd2: initial copy of files from jbd")
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-5-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index 25e3c20eb19f6..c4e0da6db7195 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -221,20 +221,6 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+ jh = transaction->t_checkpoint_list;
+ bh = jh2bh(jh);
+
+- /*
+- * The buffer may be writing back, or flushing out in the
+- * last couple of cycles, or re-adding into a new transaction,
+- * need to check it again until it's unlocked.
+- */
+- if (buffer_locked(bh)) {
+- get_bh(bh);
+- spin_unlock(&journal->j_list_lock);
+- wait_on_buffer(bh);
+- /* the journal_head may have gone by now */
+- BUFFER_TRACE(bh, "brelse");
+- __brelse(bh);
+- goto retry;
+- }
+ if (jh->b_transaction != NULL) {
+ transaction_t *t = jh->b_transaction;
+ tid_t tid = t->t_tid;
+@@ -269,7 +255,22 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+ spin_lock(&journal->j_list_lock);
+ goto restart;
+ }
+- if (!buffer_dirty(bh)) {
++ if (!trylock_buffer(bh)) {
++ /*
++ * The buffer is locked, it may be writing back, or
++ * flushing out in the last couple of cycles, or
++ * re-adding into a new transaction, need to check
++ * it again until it's unlocked.
++ */
++ get_bh(bh);
++ spin_unlock(&journal->j_list_lock);
++ wait_on_buffer(bh);
++ /* the journal_head may have gone by now */
++ BUFFER_TRACE(bh, "brelse");
++ __brelse(bh);
++ goto retry;
++ } else if (!buffer_dirty(bh)) {
++ unlock_buffer(bh);
+ BUFFER_TRACE(bh, "remove from checkpoint");
+ /*
+ * If the transaction was released or the checkpoint
+@@ -279,6 +280,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+ !transaction->t_checkpoint_list)
+ goto out;
+ } else {
++ unlock_buffer(bh);
+ /*
+ * We are about to write the buffer, it could be
+ * raced by some other transaction shrink or buffer
+--
+2.39.2
+
--- /dev/null
+From 71da043e7bda0b64713cf3496d168b8bc5b75c0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:25 +0800
+Subject: jbd2: remove journal_clean_one_cp_list()
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit b98dba273a0e47dbfade89c9af73c5b012a4eabb ]
+
+journal_clean_one_cp_list() and journal_shrink_one_cp_list() are almost
+the same, so merge them into journal_shrink_one_cp_list(), remove the
+nr_to_scan parameter, always scan and try to free the whole checkpoint
+list.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-4-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 75 +++++++++----------------------------
+ include/trace/events/jbd2.h | 12 ++----
+ 2 files changed, 21 insertions(+), 66 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index 723b4eb112828..42b34cab64fbd 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -349,50 +349,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
+
+ /* Checkpoint list management */
+
+-/*
+- * journal_clean_one_cp_list
+- *
+- * Find all the written-back checkpoint buffers in the given list and
+- * release them. If 'destroy' is set, clean all buffers unconditionally.
+- *
+- * Called with j_list_lock held.
+- * Returns 1 if we freed the transaction, 0 otherwise.
+- */
+-static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
+-{
+- struct journal_head *last_jh;
+- struct journal_head *next_jh = jh;
+-
+- if (!jh)
+- return 0;
+-
+- last_jh = jh->b_cpprev;
+- do {
+- jh = next_jh;
+- next_jh = jh->b_cpnext;
+-
+- if (!destroy && __cp_buffer_busy(jh))
+- return 0;
+-
+- if (__jbd2_journal_remove_checkpoint(jh))
+- return 1;
+- /*
+- * This function only frees up some memory
+- * if possible so we dont have an obligation
+- * to finish processing. Bail out if preemption
+- * requested:
+- */
+- if (need_resched())
+- return 0;
+- } while (jh != last_jh);
+-
+- return 0;
+-}
+-
+ /*
+ * journal_shrink_one_cp_list
+ *
+- * Find 'nr_to_scan' written-back checkpoint buffers in the given list
++ * Find all the written-back checkpoint buffers in the given list
+ * and try to release them. If the whole transaction is released, set
+ * the 'released' parameter. Return the number of released checkpointed
+ * buffers.
+@@ -400,15 +360,15 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
+ * Called with j_list_lock held.
+ */
+ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+- unsigned long *nr_to_scan,
+- bool *released)
++ bool destroy, bool *released)
+ {
+ struct journal_head *last_jh;
+ struct journal_head *next_jh = jh;
+ unsigned long nr_freed = 0;
+ int ret;
+
+- if (!jh || *nr_to_scan == 0)
++ *released = false;
++ if (!jh)
+ return 0;
+
+ last_jh = jh->b_cpprev;
+@@ -416,8 +376,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+
+- (*nr_to_scan)--;
+- if (__cp_buffer_busy(jh))
++ if (!destroy && __cp_buffer_busy(jh))
+ continue;
+
+ nr_freed++;
+@@ -429,7 +388,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+
+ if (need_resched())
+ break;
+- } while (jh != last_jh && *nr_to_scan);
++ } while (jh != last_jh);
+
+ return nr_freed;
+ }
+@@ -447,11 +406,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ unsigned long *nr_to_scan)
+ {
+ transaction_t *transaction, *last_transaction, *next_transaction;
+- bool released;
++ bool __maybe_unused released;
+ tid_t first_tid = 0, last_tid = 0, next_tid = 0;
+ tid_t tid = 0;
+ unsigned long nr_freed = 0;
+- unsigned long nr_scanned = *nr_to_scan;
++ unsigned long freed;
+
+ again:
+ spin_lock(&journal->j_list_lock);
+@@ -480,10 +439,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ transaction = next_transaction;
+ next_transaction = transaction->t_cpnext;
+ tid = transaction->t_tid;
+- released = false;
+
+- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
+- nr_to_scan, &released);
++ freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
++ false, &released);
++ nr_freed += freed;
++ (*nr_to_scan) -= min(*nr_to_scan, freed);
+ if (*nr_to_scan == 0)
+ break;
+ if (need_resched() || spin_needbreak(&journal->j_list_lock))
+@@ -504,9 +464,8 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ if (*nr_to_scan && next_tid)
+ goto again;
+ out:
+- nr_scanned -= *nr_to_scan;
+ trace_jbd2_shrink_checkpoint_list(journal, first_tid, tid, last_tid,
+- nr_freed, nr_scanned, next_tid);
++ nr_freed, next_tid);
+
+ return nr_freed;
+ }
+@@ -522,7 +481,7 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ {
+ transaction_t *transaction, *last_transaction, *next_transaction;
+- int ret;
++ bool released;
+
+ transaction = journal->j_checkpoint_transactions;
+ if (!transaction)
+@@ -533,8 +492,8 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ do {
+ transaction = next_transaction;
+ next_transaction = transaction->t_cpnext;
+- ret = journal_clean_one_cp_list(transaction->t_checkpoint_list,
+- destroy);
++ journal_shrink_one_cp_list(transaction->t_checkpoint_list,
++ destroy, &released);
+ /*
+ * This function only frees up some memory if possible so we
+ * dont have an obligation to finish processing. Bail out if
+@@ -547,7 +506,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ * avoids pointless scanning of transactions which still
+ * weren't checkpointed.
+ */
+- if (!ret)
++ if (!released)
+ return;
+ } while (transaction != last_transaction);
+ }
+diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
+index 8f5ee380d3093..5646ae15a957a 100644
+--- a/include/trace/events/jbd2.h
++++ b/include/trace/events/jbd2.h
+@@ -462,11 +462,9 @@ TRACE_EVENT(jbd2_shrink_scan_exit,
+ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+
+ TP_PROTO(journal_t *journal, tid_t first_tid, tid_t tid, tid_t last_tid,
+- unsigned long nr_freed, unsigned long nr_scanned,
+- tid_t next_tid),
++ unsigned long nr_freed, tid_t next_tid),
+
+- TP_ARGS(journal, first_tid, tid, last_tid, nr_freed,
+- nr_scanned, next_tid),
++ TP_ARGS(journal, first_tid, tid, last_tid, nr_freed, next_tid),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+@@ -474,7 +472,6 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+ __field(tid_t, tid)
+ __field(tid_t, last_tid)
+ __field(unsigned long, nr_freed)
+- __field(unsigned long, nr_scanned)
+ __field(tid_t, next_tid)
+ ),
+
+@@ -484,15 +481,14 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+ __entry->tid = tid;
+ __entry->last_tid = last_tid;
+ __entry->nr_freed = nr_freed;
+- __entry->nr_scanned = nr_scanned;
+ __entry->next_tid = next_tid;
+ ),
+
+ TP_printk("dev %d,%d shrink transaction %u-%u(%u) freed %lu "
+- "scanned %lu next transaction %u",
++ "next transaction %u",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->first_tid, __entry->tid, __entry->last_tid,
+- __entry->nr_freed, __entry->nr_scanned, __entry->next_tid)
++ __entry->nr_freed, __entry->next_tid)
+ );
+
+ #endif /* _TRACE_JBD2_H */
+--
+2.39.2
+
--- /dev/null
+From 9772b6005d10a0cfe725dba954d66e8ee6fa1e10 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:24 +0800
+Subject: jbd2: remove t_checkpoint_io_list
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit be22255360f80d3af789daad00025171a65424a5 ]
+
+Since t_checkpoint_io_list was stop using in jbd2_log_do_checkpoint()
+now, it's time to remove the whole t_checkpoint_io_list logic.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-3-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 42 ++----------------------------------------
+ fs/jbd2/commit.c | 3 +--
+ include/linux/jbd2.h | 6 ------
+ 3 files changed, 3 insertions(+), 48 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index c4e0da6db7195..723b4eb112828 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -27,7 +27,7 @@
+ *
+ * Called with j_list_lock held.
+ */
+-static inline void __buffer_unlink_first(struct journal_head *jh)
++static inline void __buffer_unlink(struct journal_head *jh)
+ {
+ transaction_t *transaction = jh->b_cp_transaction;
+
+@@ -40,23 +40,6 @@ static inline void __buffer_unlink_first(struct journal_head *jh)
+ }
+ }
+
+-/*
+- * Unlink a buffer from a transaction checkpoint(io) list.
+- *
+- * Called with j_list_lock held.
+- */
+-static inline void __buffer_unlink(struct journal_head *jh)
+-{
+- transaction_t *transaction = jh->b_cp_transaction;
+-
+- __buffer_unlink_first(jh);
+- if (transaction->t_checkpoint_io_list == jh) {
+- transaction->t_checkpoint_io_list = jh->b_cpnext;
+- if (transaction->t_checkpoint_io_list == jh)
+- transaction->t_checkpoint_io_list = NULL;
+- }
+-}
+-
+ /*
+ * Check a checkpoint buffer could be release or not.
+ *
+@@ -505,15 +488,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ break;
+ if (need_resched() || spin_needbreak(&journal->j_list_lock))
+ break;
+- if (released)
+- continue;
+-
+- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_io_list,
+- nr_to_scan, &released);
+- if (*nr_to_scan == 0)
+- break;
+- if (need_resched() || spin_needbreak(&journal->j_list_lock))
+- break;
+ } while (transaction != last_transaction);
+
+ if (transaction != last_transaction) {
+@@ -568,17 +542,6 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ */
+ if (need_resched())
+ return;
+- if (ret)
+- continue;
+- /*
+- * It is essential that we are as careful as in the case of
+- * t_checkpoint_list with removing the buffer from the list as
+- * we can possibly see not yet submitted buffers on io_list
+- */
+- ret = journal_clean_one_cp_list(transaction->
+- t_checkpoint_io_list, destroy);
+- if (need_resched())
+- return;
+ /*
+ * Stop scanning if we couldn't free the transaction. This
+ * avoids pointless scanning of transactions which still
+@@ -663,7 +626,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
+ jbd2_journal_put_journal_head(jh);
+
+ /* Is this transaction empty? */
+- if (transaction->t_checkpoint_list || transaction->t_checkpoint_io_list)
++ if (transaction->t_checkpoint_list)
+ return 0;
+
+ /*
+@@ -755,7 +718,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
+ J_ASSERT(transaction->t_forget == NULL);
+ J_ASSERT(transaction->t_shadow_list == NULL);
+ J_ASSERT(transaction->t_checkpoint_list == NULL);
+- J_ASSERT(transaction->t_checkpoint_io_list == NULL);
+ J_ASSERT(atomic_read(&transaction->t_updates) == 0);
+ J_ASSERT(journal->j_committing_transaction != transaction);
+ J_ASSERT(journal->j_running_transaction != transaction);
+diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
+index b33155dd70017..1073259902a60 100644
+--- a/fs/jbd2/commit.c
++++ b/fs/jbd2/commit.c
+@@ -1141,8 +1141,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
+ spin_lock(&journal->j_list_lock);
+ commit_transaction->t_state = T_FINISHED;
+ /* Check if the transaction can be dropped now that we are finished */
+- if (commit_transaction->t_checkpoint_list == NULL &&
+- commit_transaction->t_checkpoint_io_list == NULL) {
++ if (commit_transaction->t_checkpoint_list == NULL) {
+ __jbd2_journal_drop_transaction(journal, commit_transaction);
+ jbd2_journal_free_transaction(commit_transaction);
+ }
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index f619bae1dcc5d..91a2cf4bc5756 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -622,12 +622,6 @@ struct transaction_s
+ */
+ struct journal_head *t_checkpoint_list;
+
+- /*
+- * Doubly-linked circular list of all buffers submitted for IO while
+- * checkpointing. [j_list_lock]
+- */
+- struct journal_head *t_checkpoint_io_list;
+-
+ /*
+ * Doubly-linked circular list of metadata buffers being
+ * shadowed by log IO. The IO buffers on the iobuf list and
+--
+2.39.2
+
--- /dev/null
+From 062a794c55cbe4bc9f28d3a7dbdf77e89fd5c5d3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Jul 2023 20:32:43 +0100
+Subject: KVM: arm64: Handle kvm_arm_init failure correctly in finalize_pkvm
+
+From: Sudeep Holla <sudeep.holla@arm.com>
+
+[ Upstream commit fa729bc7c9c8c17a2481358c841ef8ca920485d3 ]
+
+Currently there is no synchronisation between finalize_pkvm() and
+kvm_arm_init() initcalls. The finalize_pkvm() proceeds happily even if
+kvm_arm_init() fails resulting in the following warning on all the CPUs
+and eventually a HYP panic:
+
+ | kvm [1]: IPA Size Limit: 48 bits
+ | kvm [1]: Failed to init hyp memory protection
+ | kvm [1]: error initializing Hyp mode: -22
+ |
+ | <snip>
+ |
+ | WARNING: CPU: 0 PID: 0 at arch/arm64/kvm/pkvm.c:226 _kvm_host_prot_finalize+0x30/0x50
+ | Modules linked in:
+ | CPU: 0 PID: 0 Comm: swapper/0 Not tainted 6.4.0 #237
+ | Hardware name: FVP Base RevC (DT)
+ | pstate: 634020c5 (nZCv daIF +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
+ | pc : _kvm_host_prot_finalize+0x30/0x50
+ | lr : __flush_smp_call_function_queue+0xd8/0x230
+ |
+ | Call trace:
+ | _kvm_host_prot_finalize+0x3c/0x50
+ | on_each_cpu_cond_mask+0x3c/0x6c
+ | pkvm_drop_host_privileges+0x4c/0x78
+ | finalize_pkvm+0x3c/0x5c
+ | do_one_initcall+0xcc/0x240
+ | do_initcall_level+0x8c/0xac
+ | do_initcalls+0x54/0x94
+ | do_basic_setup+0x1c/0x28
+ | kernel_init_freeable+0x100/0x16c
+ | kernel_init+0x20/0x1a0
+ | ret_from_fork+0x10/0x20
+ | Failed to finalize Hyp protection: -22
+ | dtb=fvp-base-revc.dtb
+ | kvm [95]: nVHE hyp BUG at: arch/arm64/kvm/hyp/nvhe/mem_protect.c:540!
+ | kvm [95]: nVHE call trace:
+ | kvm [95]: [<ffff800081052984>] __kvm_nvhe_hyp_panic+0xac/0xf8
+ | kvm [95]: [<ffff800081059644>] __kvm_nvhe_handle_host_mem_abort+0x1a0/0x2ac
+ | kvm [95]: [<ffff80008105511c>] __kvm_nvhe_handle_trap+0x4c/0x160
+ | kvm [95]: [<ffff8000810540fc>] __kvm_nvhe___skip_pauth_save+0x4/0x4
+ | kvm [95]: ---[ end nVHE call trace ]---
+ | kvm [95]: Hyp Offset: 0xfffe8db00ffa0000
+ | Kernel panic - not syncing: HYP panic:
+ | PS:a34023c9 PC:0000f250710b973c ESR:00000000f2000800
+ | FAR:ffff000800cb00d0 HPFAR:000000000880cb00 PAR:0000000000000000
+ | VCPU:0000000000000000
+ | CPU: 3 PID: 95 Comm: kworker/u16:2 Tainted: G W 6.4.0 #237
+ | Hardware name: FVP Base RevC (DT)
+ | Workqueue: rpciod rpc_async_schedule
+ | Call trace:
+ | dump_backtrace+0xec/0x108
+ | show_stack+0x18/0x2c
+ | dump_stack_lvl+0x50/0x68
+ | dump_stack+0x18/0x24
+ | panic+0x138/0x33c
+ | nvhe_hyp_panic_handler+0x100/0x184
+ | new_slab+0x23c/0x54c
+ | ___slab_alloc+0x3e4/0x770
+ | kmem_cache_alloc_node+0x1f0/0x278
+ | __alloc_skb+0xdc/0x294
+ | tcp_stream_alloc_skb+0x2c/0xf0
+ | tcp_sendmsg_locked+0x3d0/0xda4
+ | tcp_sendmsg+0x38/0x5c
+ | inet_sendmsg+0x44/0x60
+ | sock_sendmsg+0x1c/0x34
+ | xprt_sock_sendmsg+0xdc/0x274
+ | xs_tcp_send_request+0x1ac/0x28c
+ | xprt_transmit+0xcc/0x300
+ | call_transmit+0x78/0x90
+ | __rpc_execute+0x114/0x3d8
+ | rpc_async_schedule+0x28/0x48
+ | process_one_work+0x1d8/0x314
+ | worker_thread+0x248/0x474
+ | kthread+0xfc/0x184
+ | ret_from_fork+0x10/0x20
+ | SMP: stopping secondary CPUs
+ | Kernel Offset: 0x57c5cb460000 from 0xffff800080000000
+ | PHYS_OFFSET: 0x80000000
+ | CPU features: 0x00000000,1035b7a3,ccfe773f
+ | Memory Limit: none
+ | ---[ end Kernel panic - not syncing: HYP panic:
+ | PS:a34023c9 PC:0000f250710b973c ESR:00000000f2000800
+ | FAR:ffff000800cb00d0 HPFAR:000000000880cb00 PAR:0000000000000000
+ | VCPU:0000000000000000 ]---
+
+Fix it by checking for the successfull initialisation of kvm_arm_init()
+in finalize_pkvm() before proceeding any futher.
+
+Fixes: 87727ba2bb05 ("KVM: arm64: Ensure CPU PMU probes before pKVM host de-privilege")
+Cc: Will Deacon <will@kernel.org>
+Cc: Marc Zyngier <maz@kernel.org>
+Cc: Oliver Upton <oliver.upton@linux.dev>
+Cc: James Morse <james.morse@arm.com>
+Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
+Cc: Zenghui Yu <yuzenghui@huawei.com>
+Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
+Acked-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20230704193243.3300506-1-sudeep.holla@arm.com
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/virt.h | 1 +
+ arch/arm64/kvm/arm.c | 9 ++++++++-
+ arch/arm64/kvm/pkvm.c | 2 +-
+ 3 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
+index 4eb601e7de507..06382da630123 100644
+--- a/arch/arm64/include/asm/virt.h
++++ b/arch/arm64/include/asm/virt.h
+@@ -78,6 +78,7 @@ extern u32 __boot_cpu_mode[2];
+
+ void __hyp_set_vectors(phys_addr_t phys_vector_base);
+ void __hyp_reset_vectors(void);
++bool is_kvm_arm_initialised(void);
+
+ DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
+
+diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
+index 91bec8454d573..5c354a3bf7372 100644
+--- a/arch/arm64/kvm/arm.c
++++ b/arch/arm64/kvm/arm.c
+@@ -53,11 +53,16 @@ DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
+
+ DECLARE_KVM_NVHE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
+
+-static bool vgic_present;
++static bool vgic_present, kvm_arm_initialised;
+
+ static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
+ DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+
++bool is_kvm_arm_initialised(void)
++{
++ return kvm_arm_initialised;
++}
++
+ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
+ {
+ return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
+@@ -2422,6 +2427,8 @@ static __init int kvm_arm_init(void)
+ if (err)
+ goto out_subs;
+
++ kvm_arm_initialised = true;
++
+ return 0;
+
+ out_subs:
+diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
+index 6e9ece1ebbe72..3895416cb15ae 100644
+--- a/arch/arm64/kvm/pkvm.c
++++ b/arch/arm64/kvm/pkvm.c
+@@ -243,7 +243,7 @@ static int __init finalize_pkvm(void)
+ {
+ int ret;
+
+- if (!is_protected_kvm_enabled())
++ if (!is_protected_kvm_enabled() || !is_kvm_arm_initialised())
+ return 0;
+
+ /*
+--
+2.39.2
+
--- /dev/null
+From 841a52c56c2617f57497f05868863901179c458d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Jun 2023 12:25:59 +0000
+Subject: KVM: arm64: Use different pointer authentication keys for pKVM
+
+From: Mostafa Saleh <smostafa@google.com>
+
+[ Upstream commit 8c15c2a0281087d19f62d7c2b5ab1f9e961b8d97 ]
+
+When the use of pointer authentication is enabled in the kernel it
+applies to both the kernel itself as well as KVM's nVHE hypervisor. The
+same keys are used for both the kernel and the nVHE hypervisor, which is
+less than desirable for pKVM as the host is not trusted at runtime.
+
+Naturally, the fix is to use a different set of keys for the hypervisor
+when running in protected mode. Have the host generate a new set of keys
+for the hypervisor before deprivileging the kernel. While there might be
+other sources of random directly available at EL2, this keeps the
+implementation simple, and the host is trusted anyways until it is
+deprivileged.
+
+Since the host and hypervisor no longer share a set of pointer
+authentication keys, start context switching them on the host entry/exit
+path exactly as we do for guest entry/exit. There is no need to handle
+CPU migration as the nVHE code is not migratable in the first place.
+
+Signed-off-by: Mostafa Saleh <smostafa@google.com>
+Link: https://lore.kernel.org/r/20230614122600.2098901-1-smostafa@google.com
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Stable-dep-of: fa729bc7c9c8 ("KVM: arm64: Handle kvm_arm_init failure correctly in finalize_pkvm")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kvm/arm.c | 26 ++++++++++++++++++++++++
+ arch/arm64/kvm/hyp/nvhe/host.S | 36 +++++++++++++++++++++++++++++++++-
+ 2 files changed, 61 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
+index 7d8c3dd8b7ca9..91bec8454d573 100644
+--- a/arch/arm64/kvm/arm.c
++++ b/arch/arm64/kvm/arm.c
+@@ -51,6 +51,8 @@ DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
+ DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
+ DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
+
++DECLARE_KVM_NVHE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
++
+ static bool vgic_present;
+
+ static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
+@@ -2080,6 +2082,26 @@ static int __init kvm_hyp_init_protection(u32 hyp_va_bits)
+ return 0;
+ }
+
++static void pkvm_hyp_init_ptrauth(void)
++{
++ struct kvm_cpu_context *hyp_ctxt;
++ int cpu;
++
++ for_each_possible_cpu(cpu) {
++ hyp_ctxt = per_cpu_ptr_nvhe_sym(kvm_hyp_ctxt, cpu);
++ hyp_ctxt->sys_regs[APIAKEYLO_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APIAKEYHI_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APIBKEYLO_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APIBKEYHI_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APDAKEYLO_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APDAKEYHI_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APDBKEYLO_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APDBKEYHI_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APGAKEYLO_EL1] = get_random_long();
++ hyp_ctxt->sys_regs[APGAKEYHI_EL1] = get_random_long();
++ }
++}
++
+ /* Inits Hyp-mode on all online CPUs */
+ static int __init init_hyp_mode(void)
+ {
+@@ -2241,6 +2263,10 @@ static int __init init_hyp_mode(void)
+ kvm_hyp_init_symbols();
+
+ if (is_protected_kvm_enabled()) {
++ if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL) &&
++ cpus_have_const_cap(ARM64_HAS_ADDRESS_AUTH))
++ pkvm_hyp_init_ptrauth();
++
+ init_cpu_logical_map();
+
+ if (!init_psci_relay()) {
+diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S
+index b6c0188c4b35a..c87c63133e10c 100644
+--- a/arch/arm64/kvm/hyp/nvhe/host.S
++++ b/arch/arm64/kvm/hyp/nvhe/host.S
+@@ -10,6 +10,7 @@
+ #include <asm/kvm_arm.h>
+ #include <asm/kvm_asm.h>
+ #include <asm/kvm_mmu.h>
++#include <asm/kvm_ptrauth.h>
+
+ .text
+
+@@ -37,10 +38,43 @@ SYM_FUNC_START(__host_exit)
+
+ /* Save the host context pointer in x29 across the function call */
+ mov x29, x0
++
++#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
++alternative_if_not ARM64_HAS_ADDRESS_AUTH
++b __skip_pauth_save
++alternative_else_nop_endif
++
++alternative_if ARM64_KVM_PROTECTED_MODE
++ /* Save kernel ptrauth keys. */
++ add x18, x29, #CPU_APIAKEYLO_EL1
++ ptrauth_save_state x18, x19, x20
++
++ /* Use hyp keys. */
++ adr_this_cpu x18, kvm_hyp_ctxt, x19
++ add x18, x18, #CPU_APIAKEYLO_EL1
++ ptrauth_restore_state x18, x19, x20
++ isb
++alternative_else_nop_endif
++__skip_pauth_save:
++#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
++
+ bl handle_trap
+
+- /* Restore host regs x0-x17 */
+ __host_enter_restore_full:
++ /* Restore kernel keys. */
++#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
++alternative_if_not ARM64_HAS_ADDRESS_AUTH
++b __skip_pauth_restore
++alternative_else_nop_endif
++
++alternative_if ARM64_KVM_PROTECTED_MODE
++ add x18, x29, #CPU_APIAKEYLO_EL1
++ ptrauth_restore_state x18, x19, x20
++alternative_else_nop_endif
++__skip_pauth_restore:
++#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
++
++ /* Restore host regs x0-x17 */
+ ldp x0, x1, [x29, #CPU_XREG_OFFSET(0)]
+ ldp x2, x3, [x29, #CPU_XREG_OFFSET(2)]
+ ldp x4, x5, [x29, #CPU_XREG_OFFSET(4)]
+--
+2.39.2
+
--- /dev/null
+From f243e46c25a857cb3a9d4d9f440f2ef085cbaa18 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Jul 2023 13:19:37 +0200
+Subject: KVM: s390: pv: fix index value of replaced ASCE
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Claudio Imbrenda <imbrenda@linux.ibm.com>
+
+[ Upstream commit c2fceb59bbda16468bda82b002383bff59de89ab ]
+
+The index field of the struct page corresponding to a guest ASCE should
+be 0. When replacing the ASCE in s390_replace_asce(), the index of the
+new ASCE should also be set to 0.
+
+Having the wrong index might lead to the wrong addresses being passed
+around when notifying pte invalidations, and eventually to validity
+intercepts (VM crash) if the prefix gets unmapped and the notifier gets
+called with the wrong address.
+
+Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
+Fixes: faa2f72cb356 ("KVM: s390: pv: leak the topmost page table when destroy fails")
+Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
+Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
+Message-ID: <20230705111937.33472-3-imbrenda@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/mm/gmap.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
+index dc90d1eb0d554..d7e8297d5642b 100644
+--- a/arch/s390/mm/gmap.c
++++ b/arch/s390/mm/gmap.c
+@@ -2846,6 +2846,7 @@ int s390_replace_asce(struct gmap *gmap)
+ page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER);
+ if (!page)
+ return -ENOMEM;
++ page->index = 0;
+ table = page_to_virt(page);
+ memcpy(table, gmap->table, 1UL << (CRST_ALLOC_ORDER + PAGE_SHIFT));
+
+--
+2.39.2
+
--- /dev/null
+From 469d3ac7321990f1b8d55049f86b6b5d2de0705c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Jul 2023 13:19:36 +0200
+Subject: KVM: s390: pv: simplify shutdown and fix race
+
+From: Claudio Imbrenda <imbrenda@linux.ibm.com>
+
+[ Upstream commit 5ff92181577a89ed12ad4e0e5813751faf16a139 ]
+
+Simplify the shutdown of non-protected VMs. There is no need to do
+complex manipulations of the counter if it was zero.
+
+This also fixes a very rare race which caused pages to be torn down
+from the address space with a non-zero counter even on older machines
+that don't support the UVC instruction, causing a crash.
+
+Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
+Fixes: fb491d5500a7 ("KVM: s390: pv: asynchronous destroy for reboot")
+Reviewed-by: Nico Boehr <nrb@linux.ibm.com>
+Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
+Message-ID: <20230705111937.33472-2-imbrenda@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kvm/pv.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c
+index 3ce5f4351156a..899f3b8ac0110 100644
+--- a/arch/s390/kvm/pv.c
++++ b/arch/s390/kvm/pv.c
+@@ -411,8 +411,12 @@ int kvm_s390_pv_deinit_cleanup_all(struct kvm *kvm, u16 *rc, u16 *rrc)
+ u16 _rc, _rrc;
+ int cc = 0;
+
+- /* Make sure the counter does not reach 0 before calling s390_uv_destroy_range */
+- atomic_inc(&kvm->mm->context.protected_count);
++ /*
++ * Nothing to do if the counter was already 0. Otherwise make sure
++ * the counter does not reach 0 before calling s390_uv_destroy_range.
++ */
++ if (!atomic_inc_not_zero(&kvm->mm->context.protected_count))
++ return 0;
+
+ *rc = 1;
+ /* If the current VM is protected, destroy it */
+--
+2.39.2
+
--- /dev/null
+From c867abaa4f6eb560581baf1dab607c9ced885b39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 May 2023 10:55:28 -0400
+Subject: maple_tree: add __init and __exit to test module
+
+From: Liam R. Howlett <Liam.Howlett@oracle.com>
+
+[ Upstream commit eaf9790d3bc6e157a2134c01c7d707a5a712fab1 ]
+
+The test functions are not needed after the module is removed, so mark
+them as such. Add __exit to the module removal function. Some other
+variables have been marked as const static as well.
+
+Link: https://lkml.kernel.org/r/20230518145544.1722059-20-Liam.Howlett@oracle.com
+Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
+Suggested-by: Andrew Morton <akpm@linux-foundation.org>
+Cc: David Binderman <dcb314@hotmail.com>
+Cc: Peng Zhang <zhangpeng.00@bytedance.com>
+Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
+Cc: Vernon Yang <vernon2gm@gmail.com>
+Cc: Wei Yang <richard.weiyang@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 7a93c71a6714 ("maple_tree: fix 32 bit mas_next testing")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ lib/test_maple_tree.c | 158 +++++++++++++-------------
+ tools/testing/radix-tree/linux/init.h | 1 +
+ tools/testing/radix-tree/maple.c | 147 ++++++++++++------------
+ 3 files changed, 155 insertions(+), 151 deletions(-)
+
+diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c
+index f1db333270e9f..261bad680f81d 100644
+--- a/lib/test_maple_tree.c
++++ b/lib/test_maple_tree.c
+@@ -30,54 +30,54 @@
+ #else
+ #define cond_resched() do {} while (0)
+ #endif
+-static
+-int mtree_insert_index(struct maple_tree *mt, unsigned long index, gfp_t gfp)
++static int __init mtree_insert_index(struct maple_tree *mt,
++ unsigned long index, gfp_t gfp)
+ {
+ return mtree_insert(mt, index, xa_mk_value(index & LONG_MAX), gfp);
+ }
+
+-static void mtree_erase_index(struct maple_tree *mt, unsigned long index)
++static void __init mtree_erase_index(struct maple_tree *mt, unsigned long index)
+ {
+ MT_BUG_ON(mt, mtree_erase(mt, index) != xa_mk_value(index & LONG_MAX));
+ MT_BUG_ON(mt, mtree_load(mt, index) != NULL);
+ }
+
+-static int mtree_test_insert(struct maple_tree *mt, unsigned long index,
++static int __init mtree_test_insert(struct maple_tree *mt, unsigned long index,
+ void *ptr)
+ {
+ return mtree_insert(mt, index, ptr, GFP_KERNEL);
+ }
+
+-static int mtree_test_store_range(struct maple_tree *mt, unsigned long start,
+- unsigned long end, void *ptr)
++static int __init mtree_test_store_range(struct maple_tree *mt,
++ unsigned long start, unsigned long end, void *ptr)
+ {
+ return mtree_store_range(mt, start, end, ptr, GFP_KERNEL);
+ }
+
+-static int mtree_test_store(struct maple_tree *mt, unsigned long start,
++static int __init mtree_test_store(struct maple_tree *mt, unsigned long start,
+ void *ptr)
+ {
+ return mtree_test_store_range(mt, start, start, ptr);
+ }
+
+-static int mtree_test_insert_range(struct maple_tree *mt, unsigned long start,
+- unsigned long end, void *ptr)
++static int __init mtree_test_insert_range(struct maple_tree *mt,
++ unsigned long start, unsigned long end, void *ptr)
+ {
+ return mtree_insert_range(mt, start, end, ptr, GFP_KERNEL);
+ }
+
+-static void *mtree_test_load(struct maple_tree *mt, unsigned long index)
++static void __init *mtree_test_load(struct maple_tree *mt, unsigned long index)
+ {
+ return mtree_load(mt, index);
+ }
+
+-static void *mtree_test_erase(struct maple_tree *mt, unsigned long index)
++static void __init *mtree_test_erase(struct maple_tree *mt, unsigned long index)
+ {
+ return mtree_erase(mt, index);
+ }
+
+ #if defined(CONFIG_64BIT)
+-static noinline void check_mtree_alloc_range(struct maple_tree *mt,
++static noinline void __init check_mtree_alloc_range(struct maple_tree *mt,
+ unsigned long start, unsigned long end, unsigned long size,
+ unsigned long expected, int eret, void *ptr)
+ {
+@@ -94,7 +94,7 @@ static noinline void check_mtree_alloc_range(struct maple_tree *mt,
+ MT_BUG_ON(mt, result != expected);
+ }
+
+-static noinline void check_mtree_alloc_rrange(struct maple_tree *mt,
++static noinline void __init check_mtree_alloc_rrange(struct maple_tree *mt,
+ unsigned long start, unsigned long end, unsigned long size,
+ unsigned long expected, int eret, void *ptr)
+ {
+@@ -112,8 +112,8 @@ static noinline void check_mtree_alloc_rrange(struct maple_tree *mt,
+ }
+ #endif
+
+-static noinline void check_load(struct maple_tree *mt, unsigned long index,
+- void *ptr)
++static noinline void __init check_load(struct maple_tree *mt,
++ unsigned long index, void *ptr)
+ {
+ void *ret = mtree_test_load(mt, index);
+
+@@ -122,7 +122,7 @@ static noinline void check_load(struct maple_tree *mt, unsigned long index,
+ MT_BUG_ON(mt, ret != ptr);
+ }
+
+-static noinline void check_store_range(struct maple_tree *mt,
++static noinline void __init check_store_range(struct maple_tree *mt,
+ unsigned long start, unsigned long end, void *ptr, int expected)
+ {
+ int ret = -EINVAL;
+@@ -138,7 +138,7 @@ static noinline void check_store_range(struct maple_tree *mt,
+ check_load(mt, i, ptr);
+ }
+
+-static noinline void check_insert_range(struct maple_tree *mt,
++static noinline void __init check_insert_range(struct maple_tree *mt,
+ unsigned long start, unsigned long end, void *ptr, int expected)
+ {
+ int ret = -EINVAL;
+@@ -154,8 +154,8 @@ static noinline void check_insert_range(struct maple_tree *mt,
+ check_load(mt, i, ptr);
+ }
+
+-static noinline void check_insert(struct maple_tree *mt, unsigned long index,
+- void *ptr)
++static noinline void __init check_insert(struct maple_tree *mt,
++ unsigned long index, void *ptr)
+ {
+ int ret = -EINVAL;
+
+@@ -163,7 +163,7 @@ static noinline void check_insert(struct maple_tree *mt, unsigned long index,
+ MT_BUG_ON(mt, ret != 0);
+ }
+
+-static noinline void check_dup_insert(struct maple_tree *mt,
++static noinline void __init check_dup_insert(struct maple_tree *mt,
+ unsigned long index, void *ptr)
+ {
+ int ret = -EINVAL;
+@@ -173,13 +173,13 @@ static noinline void check_dup_insert(struct maple_tree *mt,
+ }
+
+
+-static noinline
+-void check_index_load(struct maple_tree *mt, unsigned long index)
++static noinline void __init check_index_load(struct maple_tree *mt,
++ unsigned long index)
+ {
+ return check_load(mt, index, xa_mk_value(index & LONG_MAX));
+ }
+
+-static inline int not_empty(struct maple_node *node)
++static inline __init int not_empty(struct maple_node *node)
+ {
+ int i;
+
+@@ -194,8 +194,8 @@ static inline int not_empty(struct maple_node *node)
+ }
+
+
+-static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max,
+- bool verbose)
++static noinline void __init check_rev_seq(struct maple_tree *mt,
++ unsigned long max, bool verbose)
+ {
+ unsigned long i = max, j;
+
+@@ -227,7 +227,7 @@ static noinline void check_rev_seq(struct maple_tree *mt, unsigned long max,
+ #endif
+ }
+
+-static noinline void check_seq(struct maple_tree *mt, unsigned long max,
++static noinline void __init check_seq(struct maple_tree *mt, unsigned long max,
+ bool verbose)
+ {
+ unsigned long i, j;
+@@ -256,7 +256,7 @@ static noinline void check_seq(struct maple_tree *mt, unsigned long max,
+ #endif
+ }
+
+-static noinline void check_lb_not_empty(struct maple_tree *mt)
++static noinline void __init check_lb_not_empty(struct maple_tree *mt)
+ {
+ unsigned long i, j;
+ unsigned long huge = 4000UL * 1000 * 1000;
+@@ -275,13 +275,13 @@ static noinline void check_lb_not_empty(struct maple_tree *mt)
+ mtree_destroy(mt);
+ }
+
+-static noinline void check_lower_bound_split(struct maple_tree *mt)
++static noinline void __init check_lower_bound_split(struct maple_tree *mt)
+ {
+ MT_BUG_ON(mt, !mtree_empty(mt));
+ check_lb_not_empty(mt);
+ }
+
+-static noinline void check_upper_bound_split(struct maple_tree *mt)
++static noinline void __init check_upper_bound_split(struct maple_tree *mt)
+ {
+ unsigned long i, j;
+ unsigned long huge;
+@@ -306,7 +306,7 @@ static noinline void check_upper_bound_split(struct maple_tree *mt)
+ mtree_destroy(mt);
+ }
+
+-static noinline void check_mid_split(struct maple_tree *mt)
++static noinline void __init check_mid_split(struct maple_tree *mt)
+ {
+ unsigned long huge = 8000UL * 1000 * 1000;
+
+@@ -315,7 +315,7 @@ static noinline void check_mid_split(struct maple_tree *mt)
+ check_lb_not_empty(mt);
+ }
+
+-static noinline void check_rev_find(struct maple_tree *mt)
++static noinline void __init check_rev_find(struct maple_tree *mt)
+ {
+ int i, nr_entries = 200;
+ void *val;
+@@ -354,7 +354,7 @@ static noinline void check_rev_find(struct maple_tree *mt)
+ rcu_read_unlock();
+ }
+
+-static noinline void check_find(struct maple_tree *mt)
++static noinline void __init check_find(struct maple_tree *mt)
+ {
+ unsigned long val = 0;
+ unsigned long count;
+@@ -571,7 +571,7 @@ static noinline void check_find(struct maple_tree *mt)
+ mtree_destroy(mt);
+ }
+
+-static noinline void check_find_2(struct maple_tree *mt)
++static noinline void __init check_find_2(struct maple_tree *mt)
+ {
+ unsigned long i, j;
+ void *entry;
+@@ -616,7 +616,7 @@ static noinline void check_find_2(struct maple_tree *mt)
+
+
+ #if defined(CONFIG_64BIT)
+-static noinline void check_alloc_rev_range(struct maple_tree *mt)
++static noinline void __init check_alloc_rev_range(struct maple_tree *mt)
+ {
+ /*
+ * Generated by:
+@@ -624,7 +624,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
+ * awk -F "-" '{printf "0x%s, 0x%s, ", $1, $2}'
+ */
+
+- unsigned long range[] = {
++ static const unsigned long range[] = {
+ /* Inclusive , Exclusive. */
+ 0x565234af2000, 0x565234af4000,
+ 0x565234af4000, 0x565234af9000,
+@@ -652,7 +652,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
+ 0x7fff58791000, 0x7fff58793000,
+ };
+
+- unsigned long holes[] = {
++ static const unsigned long holes[] = {
+ /*
+ * Note: start of hole is INCLUSIVE
+ * end of hole is EXCLUSIVE
+@@ -672,7 +672,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
+ * 4. number that should be returned.
+ * 5. return value
+ */
+- unsigned long req_range[] = {
++ static const unsigned long req_range[] = {
+ 0x565234af9000, /* Min */
+ 0x7fff58791000, /* Max */
+ 0x1000, /* Size */
+@@ -783,7 +783,7 @@ static noinline void check_alloc_rev_range(struct maple_tree *mt)
+ mtree_destroy(mt);
+ }
+
+-static noinline void check_alloc_range(struct maple_tree *mt)
++static noinline void __init check_alloc_range(struct maple_tree *mt)
+ {
+ /*
+ * Generated by:
+@@ -791,7 +791,7 @@ static noinline void check_alloc_range(struct maple_tree *mt)
+ * awk -F "-" '{printf "0x%s, 0x%s, ", $1, $2}'
+ */
+
+- unsigned long range[] = {
++ static const unsigned long range[] = {
+ /* Inclusive , Exclusive. */
+ 0x565234af2000, 0x565234af4000,
+ 0x565234af4000, 0x565234af9000,
+@@ -818,7 +818,7 @@ static noinline void check_alloc_range(struct maple_tree *mt)
+ 0x7fff5878e000, 0x7fff58791000,
+ 0x7fff58791000, 0x7fff58793000,
+ };
+- unsigned long holes[] = {
++ static const unsigned long holes[] = {
+ /* Start of hole, end of hole, size of hole (+1) */
+ 0x565234afb000, 0x565234afc000, 0x1000,
+ 0x565234afe000, 0x565235def000, 0x12F1000,
+@@ -833,7 +833,7 @@ static noinline void check_alloc_range(struct maple_tree *mt)
+ * 4. number that should be returned.
+ * 5. return value
+ */
+- unsigned long req_range[] = {
++ static const unsigned long req_range[] = {
+ 0x565234af9000, /* Min */
+ 0x7fff58791000, /* Max */
+ 0x1000, /* Size */
+@@ -942,10 +942,10 @@ static noinline void check_alloc_range(struct maple_tree *mt)
+ }
+ #endif
+
+-static noinline void check_ranges(struct maple_tree *mt)
++static noinline void __init check_ranges(struct maple_tree *mt)
+ {
+ int i, val, val2;
+- unsigned long r[] = {
++ static const unsigned long r[] = {
+ 10, 15,
+ 20, 25,
+ 17, 22, /* Overlaps previous range. */
+@@ -1210,7 +1210,7 @@ static noinline void check_ranges(struct maple_tree *mt)
+ MT_BUG_ON(mt, mt_height(mt) != 4);
+ }
+
+-static noinline void check_next_entry(struct maple_tree *mt)
++static noinline void __init check_next_entry(struct maple_tree *mt)
+ {
+ void *entry = NULL;
+ unsigned long limit = 30, i = 0;
+@@ -1234,7 +1234,7 @@ static noinline void check_next_entry(struct maple_tree *mt)
+ mtree_destroy(mt);
+ }
+
+-static noinline void check_prev_entry(struct maple_tree *mt)
++static noinline void __init check_prev_entry(struct maple_tree *mt)
+ {
+ unsigned long index = 16;
+ void *value;
+@@ -1278,7 +1278,7 @@ static noinline void check_prev_entry(struct maple_tree *mt)
+ mas_unlock(&mas);
+ }
+
+-static noinline void check_root_expand(struct maple_tree *mt)
++static noinline void __init check_root_expand(struct maple_tree *mt)
+ {
+ MA_STATE(mas, mt, 0, 0);
+ void *ptr;
+@@ -1367,13 +1367,13 @@ static noinline void check_root_expand(struct maple_tree *mt)
+ mas_unlock(&mas);
+ }
+
+-static noinline void check_gap_combining(struct maple_tree *mt)
++static noinline void __init check_gap_combining(struct maple_tree *mt)
+ {
+ struct maple_enode *mn1, *mn2;
+ void *entry;
+ unsigned long singletons = 100;
+- unsigned long *seq100;
+- unsigned long seq100_64[] = {
++ static const unsigned long *seq100;
++ static const unsigned long seq100_64[] = {
+ /* 0-5 */
+ 74, 75, 76,
+ 50, 100, 2,
+@@ -1387,7 +1387,7 @@ static noinline void check_gap_combining(struct maple_tree *mt)
+ 76, 2, 79, 85, 4,
+ };
+
+- unsigned long seq100_32[] = {
++ static const unsigned long seq100_32[] = {
+ /* 0-5 */
+ 61, 62, 63,
+ 50, 100, 2,
+@@ -1401,11 +1401,11 @@ static noinline void check_gap_combining(struct maple_tree *mt)
+ 76, 2, 79, 85, 4,
+ };
+
+- unsigned long seq2000[] = {
++ static const unsigned long seq2000[] = {
+ 1152, 1151,
+ 1100, 1200, 2,
+ };
+- unsigned long seq400[] = {
++ static const unsigned long seq400[] = {
+ 286, 318,
+ 256, 260, 266, 270, 275, 280, 290, 398,
+ 286, 310,
+@@ -1564,7 +1564,7 @@ static noinline void check_gap_combining(struct maple_tree *mt)
+ mt_set_non_kernel(0);
+ mtree_destroy(mt);
+ }
+-static noinline void check_node_overwrite(struct maple_tree *mt)
++static noinline void __init check_node_overwrite(struct maple_tree *mt)
+ {
+ int i, max = 4000;
+
+@@ -1577,7 +1577,7 @@ static noinline void check_node_overwrite(struct maple_tree *mt)
+ }
+
+ #if defined(BENCH_SLOT_STORE)
+-static noinline void bench_slot_store(struct maple_tree *mt)
++static noinline void __init bench_slot_store(struct maple_tree *mt)
+ {
+ int i, brk = 105, max = 1040, brk_start = 100, count = 20000000;
+
+@@ -1593,7 +1593,7 @@ static noinline void bench_slot_store(struct maple_tree *mt)
+ #endif
+
+ #if defined(BENCH_NODE_STORE)
+-static noinline void bench_node_store(struct maple_tree *mt)
++static noinline void __init bench_node_store(struct maple_tree *mt)
+ {
+ int i, overwrite = 76, max = 240, count = 20000000;
+
+@@ -1612,7 +1612,7 @@ static noinline void bench_node_store(struct maple_tree *mt)
+ #endif
+
+ #if defined(BENCH_AWALK)
+-static noinline void bench_awalk(struct maple_tree *mt)
++static noinline void __init bench_awalk(struct maple_tree *mt)
+ {
+ int i, max = 2500, count = 50000000;
+ MA_STATE(mas, mt, 1470, 1470);
+@@ -1629,7 +1629,7 @@ static noinline void bench_awalk(struct maple_tree *mt)
+ }
+ #endif
+ #if defined(BENCH_WALK)
+-static noinline void bench_walk(struct maple_tree *mt)
++static noinline void __init bench_walk(struct maple_tree *mt)
+ {
+ int i, max = 2500, count = 550000000;
+ MA_STATE(mas, mt, 1470, 1470);
+@@ -1646,7 +1646,7 @@ static noinline void bench_walk(struct maple_tree *mt)
+ #endif
+
+ #if defined(BENCH_MT_FOR_EACH)
+-static noinline void bench_mt_for_each(struct maple_tree *mt)
++static noinline void __init bench_mt_for_each(struct maple_tree *mt)
+ {
+ int i, count = 1000000;
+ unsigned long max = 2500, index = 0;
+@@ -1670,7 +1670,7 @@ static noinline void bench_mt_for_each(struct maple_tree *mt)
+ #endif
+
+ /* check_forking - simulate the kernel forking sequence with the tree. */
+-static noinline void check_forking(struct maple_tree *mt)
++static noinline void __init check_forking(struct maple_tree *mt)
+ {
+
+ struct maple_tree newmt;
+@@ -1709,7 +1709,7 @@ static noinline void check_forking(struct maple_tree *mt)
+ mtree_destroy(&newmt);
+ }
+
+-static noinline void check_iteration(struct maple_tree *mt)
++static noinline void __init check_iteration(struct maple_tree *mt)
+ {
+ int i, nr_entries = 125;
+ void *val;
+@@ -1777,7 +1777,7 @@ static noinline void check_iteration(struct maple_tree *mt)
+ mt_set_non_kernel(0);
+ }
+
+-static noinline void check_mas_store_gfp(struct maple_tree *mt)
++static noinline void __init check_mas_store_gfp(struct maple_tree *mt)
+ {
+
+ struct maple_tree newmt;
+@@ -1810,7 +1810,7 @@ static noinline void check_mas_store_gfp(struct maple_tree *mt)
+ }
+
+ #if defined(BENCH_FORK)
+-static noinline void bench_forking(struct maple_tree *mt)
++static noinline void __init bench_forking(struct maple_tree *mt)
+ {
+
+ struct maple_tree newmt;
+@@ -1852,15 +1852,17 @@ static noinline void bench_forking(struct maple_tree *mt)
+ }
+ #endif
+
+-static noinline void next_prev_test(struct maple_tree *mt)
++static noinline void __init next_prev_test(struct maple_tree *mt)
+ {
+ int i, nr_entries;
+ void *val;
+ MA_STATE(mas, mt, 0, 0);
+ struct maple_enode *mn;
+- unsigned long *level2;
+- unsigned long level2_64[] = {707, 1000, 710, 715, 720, 725};
+- unsigned long level2_32[] = {1747, 2000, 1750, 1755, 1760, 1765};
++ static const unsigned long *level2;
++ static const unsigned long level2_64[] = { 707, 1000, 710, 715, 720,
++ 725};
++ static const unsigned long level2_32[] = { 1747, 2000, 1750, 1755,
++ 1760, 1765};
+
+ if (MAPLE_32BIT) {
+ nr_entries = 500;
+@@ -2028,7 +2030,7 @@ static noinline void next_prev_test(struct maple_tree *mt)
+
+
+ /* Test spanning writes that require balancing right sibling or right cousin */
+-static noinline void check_spanning_relatives(struct maple_tree *mt)
++static noinline void __init check_spanning_relatives(struct maple_tree *mt)
+ {
+
+ unsigned long i, nr_entries = 1000;
+@@ -2041,7 +2043,7 @@ static noinline void check_spanning_relatives(struct maple_tree *mt)
+ mtree_store_range(mt, 9365, 9955, NULL, GFP_KERNEL);
+ }
+
+-static noinline void check_fuzzer(struct maple_tree *mt)
++static noinline void __init check_fuzzer(struct maple_tree *mt)
+ {
+ /*
+ * 1. Causes a spanning rebalance of a single root node.
+@@ -2438,7 +2440,7 @@ static noinline void check_fuzzer(struct maple_tree *mt)
+ }
+
+ /* duplicate the tree with a specific gap */
+-static noinline void check_dup_gaps(struct maple_tree *mt,
++static noinline void __init check_dup_gaps(struct maple_tree *mt,
+ unsigned long nr_entries, bool zero_start,
+ unsigned long gap)
+ {
+@@ -2478,7 +2480,7 @@ static noinline void check_dup_gaps(struct maple_tree *mt,
+ }
+
+ /* Duplicate many sizes of trees. Mainly to test expected entry values */
+-static noinline void check_dup(struct maple_tree *mt)
++static noinline void __init check_dup(struct maple_tree *mt)
+ {
+ int i;
+ int big_start = 100010;
+@@ -2566,7 +2568,7 @@ static noinline void check_dup(struct maple_tree *mt)
+ }
+ }
+
+-static noinline void check_bnode_min_spanning(struct maple_tree *mt)
++static noinline void __init check_bnode_min_spanning(struct maple_tree *mt)
+ {
+ int i = 50;
+ MA_STATE(mas, mt, 0, 0);
+@@ -2585,7 +2587,7 @@ static noinline void check_bnode_min_spanning(struct maple_tree *mt)
+ mt_set_non_kernel(0);
+ }
+
+-static noinline void check_empty_area_window(struct maple_tree *mt)
++static noinline void __init check_empty_area_window(struct maple_tree *mt)
+ {
+ unsigned long i, nr_entries = 20;
+ MA_STATE(mas, mt, 0, 0);
+@@ -2670,7 +2672,7 @@ static noinline void check_empty_area_window(struct maple_tree *mt)
+ rcu_read_unlock();
+ }
+
+-static noinline void check_empty_area_fill(struct maple_tree *mt)
++static noinline void __init check_empty_area_fill(struct maple_tree *mt)
+ {
+ const unsigned long max = 0x25D78000;
+ unsigned long size;
+@@ -2714,11 +2716,11 @@ static noinline void check_empty_area_fill(struct maple_tree *mt)
+ }
+
+ static DEFINE_MTREE(tree);
+-static int maple_tree_seed(void)
++static int __init maple_tree_seed(void)
+ {
+- unsigned long set[] = {5015, 5014, 5017, 25, 1000,
+- 1001, 1002, 1003, 1005, 0,
+- 5003, 5002};
++ unsigned long set[] = { 5015, 5014, 5017, 25, 1000,
++ 1001, 1002, 1003, 1005, 0,
++ 5003, 5002};
+ void *ptr = &set;
+
+ pr_info("\nTEST STARTING\n\n");
+@@ -2988,7 +2990,7 @@ static int maple_tree_seed(void)
+ return -EINVAL;
+ }
+
+-static void maple_tree_harvest(void)
++static void __exit maple_tree_harvest(void)
+ {
+
+ }
+diff --git a/tools/testing/radix-tree/linux/init.h b/tools/testing/radix-tree/linux/init.h
+index 1bb0afc213099..81563c3dfce79 100644
+--- a/tools/testing/radix-tree/linux/init.h
++++ b/tools/testing/radix-tree/linux/init.h
+@@ -1 +1,2 @@
+ #define __init
++#define __exit
+diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c
+index adc5392df4009..67c56e9e92606 100644
+--- a/tools/testing/radix-tree/maple.c
++++ b/tools/testing/radix-tree/maple.c
+@@ -14,6 +14,7 @@
+ #include "test.h"
+ #include <stdlib.h>
+ #include <time.h>
++#include "linux/init.h"
+
+ #define module_init(x)
+ #define module_exit(x)
+@@ -81,7 +82,7 @@ static void check_mas_alloc_node_count(struct ma_state *mas)
+ * check_new_node() - Check the creation of new nodes and error path
+ * verification.
+ */
+-static noinline void check_new_node(struct maple_tree *mt)
++static noinline void __init check_new_node(struct maple_tree *mt)
+ {
+
+ struct maple_node *mn, *mn2, *mn3;
+@@ -455,7 +456,7 @@ static noinline void check_new_node(struct maple_tree *mt)
+ /*
+ * Check erasing including RCU.
+ */
+-static noinline void check_erase(struct maple_tree *mt, unsigned long index,
++static noinline void __init check_erase(struct maple_tree *mt, unsigned long index,
+ void *ptr)
+ {
+ MT_BUG_ON(mt, mtree_test_erase(mt, index) != ptr);
+@@ -465,24 +466,24 @@ static noinline void check_erase(struct maple_tree *mt, unsigned long index,
+ #define erase_check_insert(mt, i) check_insert(mt, set[i], entry[i%2])
+ #define erase_check_erase(mt, i) check_erase(mt, set[i], entry[i%2])
+
+-static noinline void check_erase_testset(struct maple_tree *mt)
++static noinline void __init check_erase_testset(struct maple_tree *mt)
+ {
+- unsigned long set[] = { 5015, 5014, 5017, 25, 1000,
+- 1001, 1002, 1003, 1005, 0,
+- 6003, 6002, 6008, 6012, 6015,
+- 7003, 7002, 7008, 7012, 7015,
+- 8003, 8002, 8008, 8012, 8015,
+- 9003, 9002, 9008, 9012, 9015,
+- 10003, 10002, 10008, 10012, 10015,
+- 11003, 11002, 11008, 11012, 11015,
+- 12003, 12002, 12008, 12012, 12015,
+- 13003, 13002, 13008, 13012, 13015,
+- 14003, 14002, 14008, 14012, 14015,
+- 15003, 15002, 15008, 15012, 15015,
+- };
+-
+-
+- void *ptr = &set;
++ static const unsigned long set[] = { 5015, 5014, 5017, 25, 1000,
++ 1001, 1002, 1003, 1005, 0,
++ 6003, 6002, 6008, 6012, 6015,
++ 7003, 7002, 7008, 7012, 7015,
++ 8003, 8002, 8008, 8012, 8015,
++ 9003, 9002, 9008, 9012, 9015,
++ 10003, 10002, 10008, 10012, 10015,
++ 11003, 11002, 11008, 11012, 11015,
++ 12003, 12002, 12008, 12012, 12015,
++ 13003, 13002, 13008, 13012, 13015,
++ 14003, 14002, 14008, 14012, 14015,
++ 15003, 15002, 15008, 15012, 15015,
++ };
++
++
++ void *ptr = &check_erase_testset;
+ void *entry[2] = { ptr, mt };
+ void *root_node;
+
+@@ -739,7 +740,7 @@ static noinline void check_erase_testset(struct maple_tree *mt)
+ int mas_ce2_over_count(struct ma_state *mas_start, struct ma_state *mas_end,
+ void *s_entry, unsigned long s_min,
+ void *e_entry, unsigned long e_max,
+- unsigned long *set, int i, bool null_entry)
++ const unsigned long *set, int i, bool null_entry)
+ {
+ int count = 0, span = 0;
+ unsigned long retry = 0;
+@@ -969,8 +970,8 @@ static inline void *mas_range_load(struct ma_state *mas,
+ }
+
+ #if defined(CONFIG_64BIT)
+-static noinline void check_erase2_testset(struct maple_tree *mt,
+- unsigned long *set, unsigned long size)
++static noinline void __init check_erase2_testset(struct maple_tree *mt,
++ const unsigned long *set, unsigned long size)
+ {
+ int entry_count = 0;
+ int check = 0;
+@@ -1114,11 +1115,11 @@ static noinline void check_erase2_testset(struct maple_tree *mt,
+
+
+ /* These tests were pulled from KVM tree modifications which failed. */
+-static noinline void check_erase2_sets(struct maple_tree *mt)
++static noinline void __init check_erase2_sets(struct maple_tree *mt)
+ {
+ void *entry;
+ unsigned long start = 0;
+- unsigned long set[] = {
++ static const unsigned long set[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140721266458624, 140737488351231,
+ ERASE, 140721266458624, 140737488351231,
+@@ -1136,7 +1137,7 @@ ERASE, 140253902692352, 140253902864383,
+ STORE, 140253902692352, 140253902696447,
+ STORE, 140253902696448, 140253902864383,
+ };
+- unsigned long set2[] = {
++ static const unsigned long set2[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140735933583360, 140737488351231,
+ ERASE, 140735933583360, 140737488351231,
+@@ -1160,7 +1161,7 @@ STORE, 140277094813696, 140277094821887,
+ STORE, 140277094821888, 140277094825983,
+ STORE, 140735933906944, 140735933911039,
+ };
+- unsigned long set3[] = {
++ static const unsigned long set3[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140735790264320, 140737488351231,
+ ERASE, 140735790264320, 140737488351231,
+@@ -1203,7 +1204,7 @@ STORE, 47135835840512, 47135835885567,
+ STORE, 47135835885568, 47135835893759,
+ };
+
+- unsigned long set4[] = {
++ static const unsigned long set4[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140728251703296, 140737488351231,
+ ERASE, 140728251703296, 140737488351231,
+@@ -1224,7 +1225,7 @@ ERASE, 47646523277312, 47646523445247,
+ STORE, 47646523277312, 47646523400191,
+ };
+
+- unsigned long set5[] = {
++ static const unsigned long set5[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140726874062848, 140737488351231,
+ ERASE, 140726874062848, 140737488351231,
+@@ -1357,7 +1358,7 @@ STORE, 47884791619584, 47884791623679,
+ STORE, 47884791623680, 47884791627775,
+ };
+
+- unsigned long set6[] = {
++ static const unsigned long set6[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140722999021568, 140737488351231,
+ ERASE, 140722999021568, 140737488351231,
+@@ -1489,7 +1490,7 @@ ERASE, 47430432014336, 47430432022527,
+ STORE, 47430432014336, 47430432018431,
+ STORE, 47430432018432, 47430432022527,
+ };
+- unsigned long set7[] = {
++ static const unsigned long set7[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140729808330752, 140737488351231,
+ ERASE, 140729808330752, 140737488351231,
+@@ -1621,7 +1622,7 @@ ERASE, 47439987130368, 47439987138559,
+ STORE, 47439987130368, 47439987134463,
+ STORE, 47439987134464, 47439987138559,
+ };
+- unsigned long set8[] = {
++ static const unsigned long set8[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140722482974720, 140737488351231,
+ ERASE, 140722482974720, 140737488351231,
+@@ -1754,7 +1755,7 @@ STORE, 47708488638464, 47708488642559,
+ STORE, 47708488642560, 47708488646655,
+ };
+
+- unsigned long set9[] = {
++ static const unsigned long set9[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140736427839488, 140737488351231,
+ ERASE, 140736427839488, 140736427839488,
+@@ -5620,7 +5621,7 @@ ERASE, 47906195480576, 47906195480576,
+ STORE, 94641242615808, 94641242750975,
+ };
+
+- unsigned long set10[] = {
++ static const unsigned long set10[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140736427839488, 140737488351231,
+ ERASE, 140736427839488, 140736427839488,
+@@ -9484,7 +9485,7 @@ STORE, 139726599680000, 139726599684095,
+ ERASE, 47906195480576, 47906195480576,
+ STORE, 94641242615808, 94641242750975,
+ };
+- unsigned long set11[] = {
++ static const unsigned long set11[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140732658499584, 140737488351231,
+ ERASE, 140732658499584, 140732658499584,
+@@ -9510,7 +9511,7 @@ STORE, 140732658565120, 140732658569215,
+ STORE, 140732658552832, 140732658565119,
+ };
+
+- unsigned long set12[] = { /* contains 12 values. */
++ static const unsigned long set12[] = { /* contains 12 values. */
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140732658499584, 140737488351231,
+ ERASE, 140732658499584, 140732658499584,
+@@ -9537,7 +9538,7 @@ STORE, 140732658552832, 140732658565119,
+ STORE, 140014592741375, 140014592741375, /* contrived */
+ STORE, 140014592733184, 140014592741376, /* creates first entry retry. */
+ };
+- unsigned long set13[] = {
++ static const unsigned long set13[] = {
+ STORE, 140373516247040, 140373516251135,/*: ffffa2e7b0e10d80 */
+ STORE, 140373516251136, 140373516255231,/*: ffffa2e7b1195d80 */
+ STORE, 140373516255232, 140373516443647,/*: ffffa2e7b0e109c0 */
+@@ -9550,7 +9551,7 @@ STORE, 140373518684160, 140373518688254,/*: ffffa2e7b05fec00 */
+ STORE, 140373518688256, 140373518692351,/*: ffffa2e7bfbdcd80 */
+ STORE, 140373518692352, 140373518696447,/*: ffffa2e7b0749e40 */
+ };
+- unsigned long set14[] = {
++ static const unsigned long set14[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140731667996672, 140737488351231,
+ SNULL, 140731668000767, 140737488351231,
+@@ -9834,7 +9835,7 @@ SNULL, 139826136543232, 139826136809471,
+ STORE, 139826136809472, 139826136842239,
+ STORE, 139826136543232, 139826136809471,
+ };
+- unsigned long set15[] = {
++ static const unsigned long set15[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140722061451264, 140737488351231,
+ SNULL, 140722061455359, 140737488351231,
+@@ -10119,7 +10120,7 @@ STORE, 139906808958976, 139906808991743,
+ STORE, 139906808692736, 139906808958975,
+ };
+
+- unsigned long set16[] = {
++ static const unsigned long set16[] = {
+ STORE, 94174808662016, 94174809321471,
+ STORE, 94174811414528, 94174811426815,
+ STORE, 94174811426816, 94174811430911,
+@@ -10330,7 +10331,7 @@ STORE, 139921865613312, 139921865617407,
+ STORE, 139921865547776, 139921865564159,
+ };
+
+- unsigned long set17[] = {
++ static const unsigned long set17[] = {
+ STORE, 94397057224704, 94397057646591,
+ STORE, 94397057650688, 94397057691647,
+ STORE, 94397057691648, 94397057695743,
+@@ -10392,7 +10393,7 @@ STORE, 140720477511680, 140720477646847,
+ STORE, 140720478302208, 140720478314495,
+ STORE, 140720478314496, 140720478318591,
+ };
+- unsigned long set18[] = {
++ static const unsigned long set18[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140724953673728, 140737488351231,
+ SNULL, 140724953677823, 140737488351231,
+@@ -10425,7 +10426,7 @@ STORE, 140222970597376, 140222970605567,
+ ERASE, 140222970597376, 140222970605567,
+ STORE, 140222970597376, 140222970605567,
+ };
+- unsigned long set19[] = {
++ static const unsigned long set19[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140725182459904, 140737488351231,
+ SNULL, 140725182463999, 140737488351231,
+@@ -10694,7 +10695,7 @@ STORE, 140656836775936, 140656836780031,
+ STORE, 140656787476480, 140656791920639,
+ ERASE, 140656774639616, 140656779083775,
+ };
+- unsigned long set20[] = {
++ static const unsigned long set20[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140735952392192, 140737488351231,
+ SNULL, 140735952396287, 140737488351231,
+@@ -10850,7 +10851,7 @@ STORE, 140590386819072, 140590386823167,
+ STORE, 140590386823168, 140590386827263,
+ SNULL, 140590376591359, 140590376595455,
+ };
+- unsigned long set21[] = {
++ static const unsigned long set21[] = {
+ STORE, 93874710941696, 93874711363583,
+ STORE, 93874711367680, 93874711408639,
+ STORE, 93874711408640, 93874711412735,
+@@ -10920,7 +10921,7 @@ ERASE, 140708393312256, 140708393316351,
+ ERASE, 140708393308160, 140708393312255,
+ ERASE, 140708393291776, 140708393308159,
+ };
+- unsigned long set22[] = {
++ static const unsigned long set22[] = {
+ STORE, 93951397134336, 93951397183487,
+ STORE, 93951397183488, 93951397728255,
+ STORE, 93951397728256, 93951397826559,
+@@ -11047,7 +11048,7 @@ STORE, 140551361253376, 140551361519615,
+ ERASE, 140551361253376, 140551361519615,
+ };
+
+- unsigned long set23[] = {
++ static const unsigned long set23[] = {
+ STORE, 94014447943680, 94014448156671,
+ STORE, 94014450253824, 94014450257919,
+ STORE, 94014450257920, 94014450266111,
+@@ -14371,7 +14372,7 @@ SNULL, 140175956627455, 140175985139711,
+ STORE, 140175927242752, 140175956627455,
+ STORE, 140175956627456, 140175985139711,
+ };
+- unsigned long set24[] = {
++ static const unsigned long set24[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140735281639424, 140737488351231,
+ SNULL, 140735281643519, 140737488351231,
+@@ -15533,7 +15534,7 @@ ERASE, 139635393024000, 139635401412607,
+ ERASE, 139635384627200, 139635384631295,
+ ERASE, 139635384631296, 139635393019903,
+ };
+- unsigned long set25[] = {
++ static const unsigned long set25[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140737488343040, 140737488351231,
+ STORE, 140722547441664, 140737488351231,
+@@ -22321,7 +22322,7 @@ STORE, 140249652703232, 140249682087935,
+ STORE, 140249682087936, 140249710600191,
+ };
+
+- unsigned long set26[] = {
++ static const unsigned long set26[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140729464770560, 140737488351231,
+ SNULL, 140729464774655, 140737488351231,
+@@ -22345,7 +22346,7 @@ ERASE, 140109040951296, 140109040959487,
+ STORE, 140109040955392, 140109040959487,
+ ERASE, 140109040955392, 140109040959487,
+ };
+- unsigned long set27[] = {
++ static const unsigned long set27[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140726128070656, 140737488351231,
+ SNULL, 140726128074751, 140737488351231,
+@@ -22741,7 +22742,7 @@ STORE, 140415509696512, 140415535910911,
+ ERASE, 140415537422336, 140415562588159,
+ STORE, 140415482433536, 140415509696511,
+ };
+- unsigned long set28[] = {
++ static const unsigned long set28[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140722475622400, 140737488351231,
+ SNULL, 140722475626495, 140737488351231,
+@@ -22809,7 +22810,7 @@ STORE, 139918413348864, 139918413352959,
+ ERASE, 139918413316096, 139918413344767,
+ STORE, 93865848528896, 93865848664063,
+ };
+- unsigned long set29[] = {
++ static const unsigned long set29[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140734467944448, 140737488351231,
+ SNULL, 140734467948543, 140737488351231,
+@@ -23684,7 +23685,7 @@ ERASE, 140143079972864, 140143088361471,
+ ERASE, 140143205793792, 140143205797887,
+ ERASE, 140143205797888, 140143214186495,
+ };
+- unsigned long set30[] = {
++ static const unsigned long set30[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140733436743680, 140737488351231,
+ SNULL, 140733436747775, 140737488351231,
+@@ -24566,7 +24567,7 @@ ERASE, 140165225893888, 140165225897983,
+ ERASE, 140165225897984, 140165234286591,
+ ERASE, 140165058105344, 140165058109439,
+ };
+- unsigned long set31[] = {
++ static const unsigned long set31[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140730890784768, 140737488351231,
+ SNULL, 140730890788863, 140737488351231,
+@@ -25379,7 +25380,7 @@ ERASE, 140623906590720, 140623914979327,
+ ERASE, 140622950277120, 140622950281215,
+ ERASE, 140622950281216, 140622958669823,
+ };
+- unsigned long set32[] = {
++ static const unsigned long set32[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140731244212224, 140737488351231,
+ SNULL, 140731244216319, 140737488351231,
+@@ -26175,7 +26176,7 @@ ERASE, 140400417288192, 140400425676799,
+ ERASE, 140400283066368, 140400283070463,
+ ERASE, 140400283070464, 140400291459071,
+ };
+- unsigned long set33[] = {
++ static const unsigned long set33[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140734562918400, 140737488351231,
+ SNULL, 140734562922495, 140737488351231,
+@@ -26317,7 +26318,7 @@ STORE, 140582961786880, 140583003750399,
+ ERASE, 140582961786880, 140583003750399,
+ };
+
+- unsigned long set34[] = {
++ static const unsigned long set34[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140731327180800, 140737488351231,
+ SNULL, 140731327184895, 140737488351231,
+@@ -27198,7 +27199,7 @@ ERASE, 140012522094592, 140012530483199,
+ ERASE, 140012033142784, 140012033146879,
+ ERASE, 140012033146880, 140012041535487,
+ };
+- unsigned long set35[] = {
++ static const unsigned long set35[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140730536939520, 140737488351231,
+ SNULL, 140730536943615, 140737488351231,
+@@ -27955,7 +27956,7 @@ ERASE, 140474471936000, 140474480324607,
+ ERASE, 140474396430336, 140474396434431,
+ ERASE, 140474396434432, 140474404823039,
+ };
+- unsigned long set36[] = {
++ static const unsigned long set36[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140723893125120, 140737488351231,
+ SNULL, 140723893129215, 140737488351231,
+@@ -28816,7 +28817,7 @@ ERASE, 140121890357248, 140121898745855,
+ ERASE, 140121269587968, 140121269592063,
+ ERASE, 140121269592064, 140121277980671,
+ };
+- unsigned long set37[] = {
++ static const unsigned long set37[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140722404016128, 140737488351231,
+ SNULL, 140722404020223, 140737488351231,
+@@ -28942,7 +28943,7 @@ STORE, 139759821246464, 139759888355327,
+ ERASE, 139759821246464, 139759888355327,
+ ERASE, 139759888355328, 139759955464191,
+ };
+- unsigned long set38[] = {
++ static const unsigned long set38[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140730666221568, 140737488351231,
+ SNULL, 140730666225663, 140737488351231,
+@@ -29752,7 +29753,7 @@ ERASE, 140613504712704, 140613504716799,
+ ERASE, 140613504716800, 140613513105407,
+ };
+
+- unsigned long set39[] = {
++ static const unsigned long set39[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140736271417344, 140737488351231,
+ SNULL, 140736271421439, 140737488351231,
+@@ -30124,7 +30125,7 @@ STORE, 140325364428800, 140325372821503,
+ STORE, 140325356036096, 140325364428799,
+ SNULL, 140325364432895, 140325372821503,
+ };
+- unsigned long set40[] = {
++ static const unsigned long set40[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140734309167104, 140737488351231,
+ SNULL, 140734309171199, 140737488351231,
+@@ -30875,7 +30876,7 @@ ERASE, 140320289300480, 140320289304575,
+ ERASE, 140320289304576, 140320297693183,
+ ERASE, 140320163409920, 140320163414015,
+ };
+- unsigned long set41[] = {
++ static const unsigned long set41[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140728157171712, 140737488351231,
+ SNULL, 140728157175807, 140737488351231,
+@@ -31185,7 +31186,7 @@ STORE, 94376135090176, 94376135094271,
+ STORE, 94376135094272, 94376135098367,
+ SNULL, 94376135094272, 94377208836095,
+ };
+- unsigned long set42[] = {
++ static const unsigned long set42[] = {
+ STORE, 314572800, 1388314623,
+ STORE, 1462157312, 1462169599,
+ STORE, 1462169600, 1462185983,
+@@ -33862,7 +33863,7 @@ SNULL, 3798999040, 3799101439,
+ */
+ };
+
+- unsigned long set43[] = {
++ static const unsigned long set43[] = {
+ STORE, 140737488347136, 140737488351231,
+ STORE, 140734187720704, 140737488351231,
+ SNULL, 140734187724800, 140737488351231,
+@@ -34996,7 +34997,7 @@ void run_check_rcu_slowread(struct maple_tree *mt, struct rcu_test_struct *vals)
+ MT_BUG_ON(mt, !vals->seen_entry3);
+ MT_BUG_ON(mt, !vals->seen_both);
+ }
+-static noinline void check_rcu_simulated(struct maple_tree *mt)
++static noinline void __init check_rcu_simulated(struct maple_tree *mt)
+ {
+ unsigned long i, nr_entries = 1000;
+ unsigned long target = 4320;
+@@ -35157,7 +35158,7 @@ static noinline void check_rcu_simulated(struct maple_tree *mt)
+ rcu_unregister_thread();
+ }
+
+-static noinline void check_rcu_threaded(struct maple_tree *mt)
++static noinline void __init check_rcu_threaded(struct maple_tree *mt)
+ {
+ unsigned long i, nr_entries = 1000;
+ struct rcu_test_struct vals;
+@@ -35366,7 +35367,7 @@ static void check_dfs_preorder(struct maple_tree *mt)
+ /* End of depth first search tests */
+
+ /* Preallocation testing */
+-static noinline void check_prealloc(struct maple_tree *mt)
++static noinline void __init check_prealloc(struct maple_tree *mt)
+ {
+ unsigned long i, max = 100;
+ unsigned long allocated;
+@@ -35494,7 +35495,7 @@ static noinline void check_prealloc(struct maple_tree *mt)
+ /* End of preallocation testing */
+
+ /* Spanning writes, writes that span nodes and layers of the tree */
+-static noinline void check_spanning_write(struct maple_tree *mt)
++static noinline void __init check_spanning_write(struct maple_tree *mt)
+ {
+ unsigned long i, max = 5000;
+ MA_STATE(mas, mt, 1200, 2380);
+@@ -35662,7 +35663,7 @@ static noinline void check_spanning_write(struct maple_tree *mt)
+ /* End of spanning write testing */
+
+ /* Writes to a NULL area that are adjacent to other NULLs */
+-static noinline void check_null_expand(struct maple_tree *mt)
++static noinline void __init check_null_expand(struct maple_tree *mt)
+ {
+ unsigned long i, max = 100;
+ unsigned char data_end;
+@@ -35723,7 +35724,7 @@ static noinline void check_null_expand(struct maple_tree *mt)
+ /* End of NULL area expansions */
+
+ /* Checking for no memory is best done outside the kernel */
+-static noinline void check_nomem(struct maple_tree *mt)
++static noinline void __init check_nomem(struct maple_tree *mt)
+ {
+ MA_STATE(ms, mt, 1, 1);
+
+@@ -35758,7 +35759,7 @@ static noinline void check_nomem(struct maple_tree *mt)
+ mtree_destroy(mt);
+ }
+
+-static noinline void check_locky(struct maple_tree *mt)
++static noinline void __init check_locky(struct maple_tree *mt)
+ {
+ MA_STATE(ms, mt, 2, 2);
+ MA_STATE(reader, mt, 2, 2);
+--
+2.39.2
+
--- /dev/null
+From 70ce8be704471e08ed1ded16dce6133861ad57bc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Jul 2023 13:39:15 -0400
+Subject: maple_tree: fix 32 bit mas_next testing
+
+From: Liam R. Howlett <Liam.Howlett@oracle.com>
+
+[ Upstream commit 7a93c71a6714ca1a9c03d70432dac104b0cfb815 ]
+
+The test setup of mas_next is dependent on node entry size to create a 2
+level tree, but the tests did not account for this in the expected value
+when shifting beyond the scope of the tree.
+
+Fix this by setting up the test to succeed depending on the node entries
+which is dependent on the 32/64 bit setup.
+
+Link: https://lkml.kernel.org/r/20230712173916.168805-1-Liam.Howlett@oracle.com
+Fixes: 120b116208a0 ("maple_tree: reorganize testing to restore module testing")
+Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
+Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>
+ Closes: https://lore.kernel.org/linux-mm/CAMuHMdV4T53fOw7VPoBgPR7fP6RYqf=CBhD_y_vOg53zZX_DnA@mail.gmail.com/
+Tested-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ lib/test_maple_tree.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c
+index 261bad680f81d..fad668042f3e7 100644
+--- a/lib/test_maple_tree.c
++++ b/lib/test_maple_tree.c
+@@ -1863,13 +1863,16 @@ static noinline void __init next_prev_test(struct maple_tree *mt)
+ 725};
+ static const unsigned long level2_32[] = { 1747, 2000, 1750, 1755,
+ 1760, 1765};
++ unsigned long last_index;
+
+ if (MAPLE_32BIT) {
+ nr_entries = 500;
+ level2 = level2_32;
++ last_index = 0x138e;
+ } else {
+ nr_entries = 200;
+ level2 = level2_64;
++ last_index = 0x7d6;
+ }
+
+ for (i = 0; i <= nr_entries; i++)
+@@ -1976,7 +1979,7 @@ static noinline void __init next_prev_test(struct maple_tree *mt)
+
+ val = mas_next(&mas, ULONG_MAX);
+ MT_BUG_ON(mt, val != NULL);
+- MT_BUG_ON(mt, mas.index != ULONG_MAX);
++ MT_BUG_ON(mt, mas.index != last_index);
+ MT_BUG_ON(mt, mas.last != ULONG_MAX);
+
+ val = mas_prev(&mas, 0);
+--
+2.39.2
+
--- /dev/null
+From bd5edafac2d5bada2e3c3c9d8e6130cb31bc599c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 May 2023 11:39:23 +0300
+Subject: PCI/ASPM: Avoid link retraining race
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit e7e39756363ad5bd83ddeae1063193d0f13870fd ]
+
+PCIe r6.0.1, sec 7.5.3.7, recommends setting the link control parameters,
+then waiting for the Link Training bit to be clear before setting the
+Retrain Link bit.
+
+This avoids a race where the LTSSM may not use the updated parameters if it
+is already in the midst of link training because of other normal link
+activity.
+
+Wait for the Link Training bit to be clear before toggling the Retrain Link
+bit to ensure that the LTSSM uses the updated link control parameters.
+
+[bhelgaas: commit log, return 0 (success)/-ETIMEDOUT instead of bool for
+both pcie_wait_for_retrain() and the existing pcie_retrain_link()]
+Suggested-by: Lukas Wunner <lukas@wunner.de>
+Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support")
+Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Lukas Wunner <lukas@wunner.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index 517f834ac93ef..998e26de2ad76 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -213,8 +213,19 @@ static int pcie_wait_for_retrain(struct pci_dev *pdev)
+ static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+ struct pci_dev *parent = link->pdev;
++ int rc;
+ u16 reg16;
+
++ /*
++ * Ensure the updated LNKCTL parameters are used during link
++ * training by checking that there is no ongoing link training to
++ * avoid LTSSM race as recommended in Implementation Note at the
++ * end of PCIe r6.0.1 sec 7.5.3.7.
++ */
++ rc = pcie_wait_for_retrain(parent);
++ if (rc)
++ return rc;
++
+ pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
+ reg16 |= PCI_EXP_LNKCTL_RL;
+ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+--
+2.39.2
+
--- /dev/null
+From 85d942da42fa56b093da20dba0d6276bbab4acad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Jun 2023 14:49:33 -0500
+Subject: PCI/ASPM: Factor out pcie_wait_for_retrain()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit 9c7f136433d26592cb4d9cd00b4e15c33d9797c6 ]
+
+Factor pcie_wait_for_retrain() out from pcie_retrain_link(). No functional
+change intended.
+
+[bhelgaas: split out from
+https: //lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com]
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: e7e39756363a ("PCI/ASPM: Avoid link retraining race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index 88aca887e3120..517f834ac93ef 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -193,10 +193,26 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
+ link->clkpm_disable = blacklist ? 1 : 0;
+ }
+
++static int pcie_wait_for_retrain(struct pci_dev *pdev)
++{
++ unsigned long end_jiffies;
++ u16 reg16;
++
++ /* Wait for Link Training to be cleared by hardware */
++ end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
++ do {
++ pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, ®16);
++ if (!(reg16 & PCI_EXP_LNKSTA_LT))
++ return 0;
++ msleep(1);
++ } while (time_before(jiffies, end_jiffies));
++
++ return -ETIMEDOUT;
++}
++
+ static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+ struct pci_dev *parent = link->pdev;
+- unsigned long end_jiffies;
+ u16 reg16;
+
+ pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
+@@ -212,17 +228,7 @@ static int pcie_retrain_link(struct pcie_link_state *link)
+ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+ }
+
+- /* Wait for link training end. Break out after waiting for timeout */
+- end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
+- do {
+- pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16);
+- if (!(reg16 & PCI_EXP_LNKSTA_LT))
+- break;
+- msleep(1);
+- } while (time_before(jiffies, end_jiffies));
+- if (reg16 & PCI_EXP_LNKSTA_LT)
+- return -ETIMEDOUT;
+- return 0;
++ return pcie_wait_for_retrain(parent);
+ }
+
+ /*
+--
+2.39.2
+
--- /dev/null
+From 7cbdb06af5a883cb8e66abd4dcf067b78ee85ee3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Jun 2023 14:44:55 -0500
+Subject: PCI/ASPM: Return 0 or -ETIMEDOUT from pcie_retrain_link()
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit f5297a01ee805d7fa569d288ed65fc0f9ac9b03d ]
+
+"pcie_retrain_link" is not a question with a true/false answer, so "bool"
+isn't quite the right return type. Return 0 for success or -ETIMEDOUT if
+the retrain failed. No functional change intended.
+
+[bhelgaas: based on Ilpo's patch below]
+Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: e7e39756363a ("PCI/ASPM: Avoid link retraining race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index db32335039d61..88aca887e3120 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -193,7 +193,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
+ link->clkpm_disable = blacklist ? 1 : 0;
+ }
+
+-static bool pcie_retrain_link(struct pcie_link_state *link)
++static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+ struct pci_dev *parent = link->pdev;
+ unsigned long end_jiffies;
+@@ -220,7 +220,9 @@ static bool pcie_retrain_link(struct pcie_link_state *link)
+ break;
+ msleep(1);
+ } while (time_before(jiffies, end_jiffies));
+- return !(reg16 & PCI_EXP_LNKSTA_LT);
++ if (reg16 & PCI_EXP_LNKSTA_LT)
++ return -ETIMEDOUT;
++ return 0;
+ }
+
+ /*
+@@ -289,15 +291,15 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
+ reg16 &= ~PCI_EXP_LNKCTL_CCC;
+ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+
+- if (pcie_retrain_link(link))
+- return;
++ if (pcie_retrain_link(link)) {
+
+- /* Training failed. Restore common clock configurations */
+- pci_err(parent, "ASPM: Could not configure common clock\n");
+- list_for_each_entry(child, &linkbus->devices, bus_list)
+- pcie_capability_write_word(child, PCI_EXP_LNKCTL,
++ /* Training failed. Restore common clock configurations */
++ pci_err(parent, "ASPM: Could not configure common clock\n");
++ list_for_each_entry(child, &linkbus->devices, bus_list)
++ pcie_capability_write_word(child, PCI_EXP_LNKCTL,
+ child_reg[PCI_FUNC(child->devfn)]);
+- pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
++ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
++ }
+ }
+
+ /* Convert L0s latency encoding to ns */
+--
+2.39.2
+
--- /dev/null
+From 1e27f3af80b7048100155c7c9cbdf69e94d2c81b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:57 +0200
+Subject: PCI: rockchip: Don't advertise MSI-X in PCIe capabilities
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit a52587e0bee14cbeeadf48a24013828cb04b8df8 ]
+
+The RK3399 PCIe endpoint controller cannot generate MSI-X IRQs.
+This is documented in the RK3399 technical reference manual (TRM)
+section 17.5.9 "Interrupt Support".
+
+MSI-X capability should therefore not be advertised. Remove the
+MSI-X capability by editing the capability linked-list. The
+previous entry is the MSI capability, therefore get the next
+entry from the MSI-X capability entry and set it as next entry
+for the MSI capability. This in effect removes MSI-X from the list.
+
+Linked list before : MSI cap -> MSI-X cap -> PCIe Device cap -> ...
+Linked list now : MSI cap -> PCIe Device cap -> ...
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-11-rick.wertenbroek@gmail.com
+Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller")
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 24 +++++++++++++++++++++++
+ drivers/pci/controller/pcie-rockchip.h | 5 +++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 3d6f828d29fc2..0af0e965fb57e 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -508,6 +508,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+ size_t max_regions;
+ struct pci_epc_mem_window *windows = NULL;
+ int err, i;
++ u32 cfg_msi, cfg_msix_cp;
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+@@ -583,6 +584,29 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+
+ ep->irq_pci_addr = ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR;
+
++ /*
++ * MSI-X is not supported but the controller still advertises the MSI-X
++ * capability by default, which can lead to the Root Complex side
++ * allocating MSI-X vectors which cannot be used. Avoid this by skipping
++ * the MSI-X capability entry in the PCIe capabilities linked-list: get
++ * the next pointer from the MSI-X entry and set that in the MSI
++ * capability entry (which is the previous entry). This way the MSI-X
++ * entry is skipped (left out of the linked-list) and not advertised.
++ */
++ cfg_msi = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_BASE +
++ ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
++
++ cfg_msi &= ~ROCKCHIP_PCIE_EP_MSI_CP1_MASK;
++
++ cfg_msix_cp = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_BASE +
++ ROCKCHIP_PCIE_EP_MSIX_CAP_REG) &
++ ROCKCHIP_PCIE_EP_MSIX_CAP_CP_MASK;
++
++ cfg_msi |= cfg_msix_cp;
++
++ rockchip_pcie_write(rockchip, cfg_msi,
++ PCIE_EP_CONFIG_BASE + ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
++
+ rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE,
+ PCIE_CLIENT_CONFIG);
+
+diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
+index 501d859420b4c..fe0333778fd93 100644
+--- a/drivers/pci/controller/pcie-rockchip.h
++++ b/drivers/pci/controller/pcie-rockchip.h
+@@ -227,6 +227,8 @@
+ #define ROCKCHIP_PCIE_EP_CMD_STATUS 0x4
+ #define ROCKCHIP_PCIE_EP_CMD_STATUS_IS BIT(19)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_REG 0x90
++#define ROCKCHIP_PCIE_EP_MSI_CP1_OFFSET 8
++#define ROCKCHIP_PCIE_EP_MSI_CP1_MASK GENMASK(15, 8)
+ #define ROCKCHIP_PCIE_EP_MSI_FLAGS_OFFSET 16
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET 17
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_MASK GENMASK(19, 17)
+@@ -234,6 +236,9 @@
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK GENMASK(22, 20)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_ME BIT(16)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP BIT(24)
++#define ROCKCHIP_PCIE_EP_MSIX_CAP_REG 0xb0
++#define ROCKCHIP_PCIE_EP_MSIX_CAP_CP_OFFSET 8
++#define ROCKCHIP_PCIE_EP_MSIX_CAP_CP_MASK GENMASK(15, 8)
+ #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR 0x1
+ #define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR 0x3
+ #define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \
+--
+2.39.2
+
--- /dev/null
+From 4c0faa8d031319c8b43cf3065f2f851c621e3957 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:55 +0200
+Subject: PCI: rockchip: Fix window mapping and address translation for
+ endpoint
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit dc73ed0f1b8bddd7f2bf70d123e68ffc99ad71ce ]
+
+The RK3399 PCI endpoint core has 33 windows for PCIe space, now in the
+driver up to 32 fixed size (1M) windows are used and pages are allocated
+and mapped accordingly. The driver first used a single window and allocated
+space inside which caused translation issues (between CPU space and PCI
+space) because a window can only have a single translation at a given
+time, which if multiple pages are allocated inside will cause conflicts.
+Now each window is a single region of 1M which will always guarantee that
+the translation is not in conflict.
+
+Set the translation register addresses for physical function. As documented
+in the technical reference manual (TRM) section 17.5.5 "PCIe Address
+Translation" and section 17.6.8 "Address Translation Registers Description"
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-9-rick.wertenbroek@gmail.com
+Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller")
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 128 ++++++++++------------
+ drivers/pci/controller/pcie-rockchip.h | 35 +++---
+ 2 files changed, 75 insertions(+), 88 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 9e17f3dba743a..3d6f828d29fc2 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -64,52 +64,29 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip,
+ }
+
+ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+- u32 r, u32 type, u64 cpu_addr,
+- u64 pci_addr, size_t size)
++ u32 r, u64 cpu_addr, u64 pci_addr,
++ size_t size)
+ {
+- u64 sz = 1ULL << fls64(size - 1);
+- int num_pass_bits = ilog2(sz);
+- u32 addr0, addr1, desc0, desc1;
+- bool is_nor_msg = (type == AXI_WRAPPER_NOR_MSG);
++ int num_pass_bits = fls64(size - 1);
++ u32 addr0, addr1, desc0;
+
+- /* The minimal region size is 1MB */
+ if (num_pass_bits < 8)
+ num_pass_bits = 8;
+
+- cpu_addr -= rockchip->mem_res->start;
+- addr0 = ((is_nor_msg ? 0x10 : (num_pass_bits - 1)) &
+- PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
+- (lower_32_bits(cpu_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+- addr1 = upper_32_bits(is_nor_msg ? cpu_addr : pci_addr);
+- desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | type;
+- desc1 = 0;
+-
+- if (is_nor_msg) {
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
+- rockchip_pcie_write(rockchip, desc0,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
+- rockchip_pcie_write(rockchip, desc1,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+- } else {
+- /* PCI bus address region */
+- rockchip_pcie_write(rockchip, addr0,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
+- rockchip_pcie_write(rockchip, addr1,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
+- rockchip_pcie_write(rockchip, desc0,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
+- rockchip_pcie_write(rockchip, desc1,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+-
+- addr0 =
+- ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
+- (lower_32_bits(cpu_addr) &
+- PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+- addr1 = upper_32_bits(cpu_addr);
+- }
++ addr0 = ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
++ (lower_32_bits(pci_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
++ addr1 = upper_32_bits(pci_addr);
++ desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | AXI_WRAPPER_MEM_WRITE;
++
++ /* PCI bus address region */
++ rockchip_pcie_write(rockchip, addr0,
++ ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
++ rockchip_pcie_write(rockchip, addr1,
++ ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
++ rockchip_pcie_write(rockchip, desc0,
++ ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
++ rockchip_pcie_write(rockchip, 0,
++ ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+ }
+
+ static int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+@@ -248,26 +225,20 @@ static void rockchip_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn,
+ ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar));
+ }
+
++static inline u32 rockchip_ob_region(phys_addr_t addr)
++{
++ return (addr >> ilog2(SZ_1M)) & 0x1f;
++}
++
+ static int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+ phys_addr_t addr, u64 pci_addr,
+ size_t size)
+ {
+ struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
+ struct rockchip_pcie *pcie = &ep->rockchip;
+- u32 r;
++ u32 r = rockchip_ob_region(addr);
+
+- r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG);
+- /*
+- * Region 0 is reserved for configuration space and shouldn't
+- * be used elsewhere per TRM, so leave it out.
+- */
+- if (r >= ep->max_regions - 1) {
+- dev_err(&epc->dev, "no free outbound region\n");
+- return -EINVAL;
+- }
+-
+- rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, AXI_WRAPPER_MEM_WRITE, addr,
+- pci_addr, size);
++ rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, addr, pci_addr, size);
+
+ set_bit(r, &ep->ob_region_map);
+ ep->ob_addr[r] = addr;
+@@ -282,15 +253,11 @@ static void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+ struct rockchip_pcie *rockchip = &ep->rockchip;
+ u32 r;
+
+- for (r = 0; r < ep->max_regions - 1; r++)
++ for (r = 0; r < ep->max_regions; r++)
+ if (ep->ob_addr[r] == addr)
+ break;
+
+- /*
+- * Region 0 is reserved for configuration space and shouldn't
+- * be used elsewhere per TRM, so leave it out.
+- */
+- if (r == ep->max_regions - 1)
++ if (r == ep->max_regions)
+ return;
+
+ rockchip_pcie_clear_ep_ob_atu(rockchip, r);
+@@ -387,7 +354,8 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
+ struct rockchip_pcie *rockchip = &ep->rockchip;
+ u32 flags, mme, data, data_mask;
+ u8 msi_count;
+- u64 pci_addr, pci_addr_mask = 0xff;
++ u64 pci_addr;
++ u32 r;
+
+ /* Check MSI enable bit */
+ flags = rockchip_pcie_read(&ep->rockchip,
+@@ -421,21 +389,20 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
+ ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
+ ROCKCHIP_PCIE_EP_MSI_CTRL_REG +
+ PCI_MSI_ADDRESS_LO);
+- pci_addr &= GENMASK_ULL(63, 2);
+
+ /* Set the outbound region if needed. */
+- if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
++ if (unlikely(ep->irq_pci_addr != (pci_addr & PCIE_ADDR_MASK) ||
+ ep->irq_pci_fn != fn)) {
+- rockchip_pcie_prog_ep_ob_atu(rockchip, fn, ep->max_regions - 1,
+- AXI_WRAPPER_MEM_WRITE,
++ r = rockchip_ob_region(ep->irq_phys_addr);
++ rockchip_pcie_prog_ep_ob_atu(rockchip, fn, r,
+ ep->irq_phys_addr,
+- pci_addr & ~pci_addr_mask,
+- pci_addr_mask + 1);
+- ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
++ pci_addr & PCIE_ADDR_MASK,
++ ~PCIE_ADDR_MASK + 1);
++ ep->irq_pci_addr = (pci_addr & PCIE_ADDR_MASK);
+ ep->irq_pci_fn = fn;
+ }
+
+- writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
++ writew(data, ep->irq_cpu_addr + (pci_addr & ~PCIE_ADDR_MASK));
+ return 0;
+ }
+
+@@ -517,6 +484,8 @@ static int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip,
+ if (err < 0 || ep->max_regions > MAX_REGION_LIMIT)
+ ep->max_regions = MAX_REGION_LIMIT;
+
++ ep->ob_region_map = 0;
++
+ err = of_property_read_u8(dev->of_node, "max-functions",
+ &ep->epc->max_functions);
+ if (err < 0)
+@@ -537,7 +506,8 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+ struct rockchip_pcie *rockchip;
+ struct pci_epc *epc;
+ size_t max_regions;
+- int err;
++ struct pci_epc_mem_window *windows = NULL;
++ int err, i;
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+@@ -584,15 +554,27 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+ /* Only enable function 0 by default */
+ rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG);
+
+- err = pci_epc_mem_init(epc, rockchip->mem_res->start,
+- resource_size(rockchip->mem_res), PAGE_SIZE);
++ windows = devm_kcalloc(dev, ep->max_regions,
++ sizeof(struct pci_epc_mem_window), GFP_KERNEL);
++ if (!windows) {
++ err = -ENOMEM;
++ goto err_uninit_port;
++ }
++ for (i = 0; i < ep->max_regions; i++) {
++ windows[i].phys_base = rockchip->mem_res->start + (SZ_1M * i);
++ windows[i].size = SZ_1M;
++ windows[i].page_size = SZ_1M;
++ }
++ err = pci_epc_multi_mem_init(epc, windows, ep->max_regions);
++ devm_kfree(dev, windows);
++
+ if (err < 0) {
+ dev_err(dev, "failed to initialize the memory space\n");
+ goto err_uninit_port;
+ }
+
+ ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
+- SZ_128K);
++ SZ_1M);
+ if (!ep->irq_cpu_addr) {
+ dev_err(dev, "failed to reserve memory space for MSI\n");
+ err = -ENOMEM;
+diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
+index 8e92dc3339ecc..501d859420b4c 100644
+--- a/drivers/pci/controller/pcie-rockchip.h
++++ b/drivers/pci/controller/pcie-rockchip.h
+@@ -139,6 +139,7 @@
+
+ #define PCIE_RC_RP_ATS_BASE 0x400000
+ #define PCIE_RC_CONFIG_NORMAL_BASE 0x800000
++#define PCIE_EP_PF_CONFIG_REGS_BASE 0x800000
+ #define PCIE_RC_CONFIG_BASE 0xa00000
+ #define PCIE_EP_CONFIG_BASE 0xa00000
+ #define PCIE_EP_CONFIG_DID_VID (PCIE_EP_CONFIG_BASE + 0x00)
+@@ -157,10 +158,11 @@
+ #define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274)
+ #define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20)
+
++#define PCIE_ADDR_MASK 0xffffff00
+ #define PCIE_CORE_AXI_CONF_BASE 0xc00000
+ #define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0)
+ #define PCIE_CORE_OB_REGION_ADDR0_NUM_BITS 0x3f
+-#define PCIE_CORE_OB_REGION_ADDR0_LO_ADDR 0xffffff00
++#define PCIE_CORE_OB_REGION_ADDR0_LO_ADDR PCIE_ADDR_MASK
+ #define PCIE_CORE_OB_REGION_ADDR1 (PCIE_CORE_AXI_CONF_BASE + 0x4)
+ #define PCIE_CORE_OB_REGION_DESC0 (PCIE_CORE_AXI_CONF_BASE + 0x8)
+ #define PCIE_CORE_OB_REGION_DESC1 (PCIE_CORE_AXI_CONF_BASE + 0xc)
+@@ -168,7 +170,7 @@
+ #define PCIE_CORE_AXI_INBOUND_BASE 0xc00800
+ #define PCIE_RP_IB_ADDR0 (PCIE_CORE_AXI_INBOUND_BASE + 0x0)
+ #define PCIE_CORE_IB_REGION_ADDR0_NUM_BITS 0x3f
+-#define PCIE_CORE_IB_REGION_ADDR0_LO_ADDR 0xffffff00
++#define PCIE_CORE_IB_REGION_ADDR0_LO_ADDR PCIE_ADDR_MASK
+ #define PCIE_RP_IB_ADDR1 (PCIE_CORE_AXI_INBOUND_BASE + 0x4)
+
+ /* Size of one AXI Region (not Region 0) */
+@@ -233,13 +235,15 @@
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_ME BIT(16)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP BIT(24)
+ #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR 0x1
+-#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))
++#define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR 0x3
++#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \
++ (PCIE_EP_PF_CONFIG_REGS_BASE + (((fn) << 12) & GENMASK(19, 12)))
++#define ROCKCHIP_PCIE_EP_VIRT_FUNC_BASE(fn) \
++ (PCIE_EP_PF_CONFIG_REGS_BASE + 0x10000 + (((fn) << 12) & GENMASK(19, 12)))
+ #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
+- (PCIE_RC_RP_ATS_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
++ (PCIE_CORE_AXI_CONF_BASE + 0x0828 + (fn) * 0x0040 + (bar) * 0x0008)
+ #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
+- (PCIE_RC_RP_ATS_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
++ (PCIE_CORE_AXI_CONF_BASE + 0x082c + (fn) * 0x0040 + (bar) * 0x0008)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+ (((devfn) << 12) & \
+@@ -247,20 +251,21 @@
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+ (((bus) << 20) & ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
++#define PCIE_RC_EP_ATR_OB_REGIONS_1_32 (PCIE_CORE_AXI_CONF_BASE + 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0000 + ((r) & 0x1f) * 0x0020)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0004 + ((r) & 0x1f) * 0x0020)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
+ (((devfn) << 24) & ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0008 + ((r) & 0x1f) * 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r) \
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x000c + ((r) & 0x1f) * 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_DESC2(r) \
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0010 + ((r) & 0x1f) * 0x0020)
+
+ #define ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG0(fn) \
+ (PCIE_CORE_CTRL_MGMT_BASE + 0x0240 + (fn) * 0x0008)
+--
+2.39.2
+
--- /dev/null
+From 9e74dafdfa2e6fbe32bea61d9e2d6651986d3886 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:48 +0200
+Subject: PCI: rockchip: Remove writes to unused registers
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit 92a9c57c325dd51682d428ba960d961fec3c8a08 ]
+
+Remove write accesses to registers that are marked "unused" (and
+therefore read-only) in the technical reference manual (TRM)
+(see RK3399 TRM 17.6.8.1)
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-2-rick.wertenbroek@gmail.com
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Stable-dep-of: dc73ed0f1b8b ("PCI: rockchip: Fix window mapping and address translation for endpoint")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 827d91e73efab..9e17f3dba743a 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -61,10 +61,6 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip,
+ ROCKCHIP_PCIE_AT_OB_REGION_DESC0(region));
+ rockchip_pcie_write(rockchip, 0,
+ ROCKCHIP_PCIE_AT_OB_REGION_DESC1(region));
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(region));
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(region));
+ }
+
+ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+@@ -114,12 +110,6 @@ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+ PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+ addr1 = upper_32_bits(cpu_addr);
+ }
+-
+- /* CPU bus address region */
+- rockchip_pcie_write(rockchip, addr0,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r));
+- rockchip_pcie_write(rockchip, addr1,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r));
+ }
+
+ static int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+--
+2.39.2
+
--- /dev/null
+From bf2fb3cbff40cf4d6375d9d8481592a20bfa3ff3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 16 Jul 2023 03:05:06 -0700
+Subject: powerpc/pseries/vas: Hold mmap_mutex after mmap lock during window
+ close
+
+From: Haren Myneni <haren@linux.ibm.com>
+
+[ Upstream commit b59c9dc4d9d47b3c4572d826603fde507055b656 ]
+
+Commit 8ef7b9e1765a ("powerpc/pseries/vas: Close windows with DLPAR
+core removal") unmaps the window paste address and issues HCALL to
+close window in the hypervisor for migration or DLPAR core removal
+events. So holds mmap_mutex and then mmap lock before unmap the
+paste address. But if the user space issue mmap paste address at
+the same time with the migration event, coproc_mmap() is called
+after holding the mmap lock which can trigger deadlock when trying
+to acquire mmap_mutex in coproc_mmap().
+
+t1: mmap() call to mmap t2: Migration event
+ window paste address
+
+do_mmap2() migration_store()
+ ksys_mmap_pgoff() pseries_migrate_partition()
+ vm_mmap_pgoff() vas_migration_handler()
+ Acquire mmap lock reconfig_close_windows()
+ do_mmap() lock mmap_mutex
+ mmap_region() Acquire mmap lock
+ call_mmap() //Wait for mmap lock
+ coproc_mmap() unmap vma
+ lock mmap_mutex update window status
+ //wait for mmap_mutex Release mmap lock
+ mmap vma unlock mmap_mutex
+ update window status
+ unlock mmap_mutex
+ ...
+ Release mmap lock
+
+Fix this deadlock issue by holding mmap lock first before mmap_mutex
+in reconfig_close_windows().
+
+Fixes: 8ef7b9e1765a ("powerpc/pseries/vas: Close windows with DLPAR core removal")
+Signed-off-by: Haren Myneni <haren@linux.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://msgid.link/20230716100506.7833-1-haren@linux.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/platforms/pseries/vas.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
+index 9a44a98ba3420..3fbc2a6aa319d 100644
+--- a/arch/powerpc/platforms/pseries/vas.c
++++ b/arch/powerpc/platforms/pseries/vas.c
+@@ -744,6 +744,12 @@ static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds,
+ }
+
+ task_ref = &win->vas_win.task_ref;
++ /*
++ * VAS mmap (coproc_mmap()) and its fault handler
++ * (vas_mmap_fault()) are called after holding mmap lock.
++ * So hold mmap mutex after mmap_lock to avoid deadlock.
++ */
++ mmap_write_lock(task_ref->mm);
+ mutex_lock(&task_ref->mmap_mutex);
+ vma = task_ref->vma;
+ /*
+@@ -752,7 +758,6 @@ static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds,
+ */
+ win->vas_win.status |= flag;
+
+- mmap_write_lock(task_ref->mm);
+ /*
+ * vma is set in the original mapping. But this mapping
+ * is done with mmap() after the window is opened with ioctl.
+@@ -762,8 +767,8 @@ static int reconfig_close_windows(struct vas_caps *vcap, int excess_creds,
+ if (vma)
+ zap_vma_pages(vma);
+
+- mmap_write_unlock(task_ref->mm);
+ mutex_unlock(&task_ref->mmap_mutex);
++ mmap_write_unlock(task_ref->mm);
+ /*
+ * Close VAS window in the hypervisor, but do not
+ * free vas_window struct since it may be reused
+--
+2.39.2
+
--- /dev/null
+From c2a44187248c0e3c4131846b1e79fa02f3905eb3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Jul 2023 20:28:47 -0700
+Subject: regmap: Disable locking for RBTREE and MAPLE unit tests
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit a9e26169cfda651802f88262a315146fbe4bc74c ]
+
+REGCACHE_RBTREE and REGCACHE_MAPLE dynamically allocate memory
+for regmap operations. This is incompatible with spinlock based locking
+which is used for fast_io operations. Disable locking for the associated
+unit tests to avoid lockdep splashes.
+
+Fixes: f033c26de5a5 ("regmap: Add maple tree based register cache")
+Fixes: 2238959b6ad2 ("regmap: Add some basic kunit tests")
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20230720032848.1306349-1-linux@roeck-us.net
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/regmap/regmap-kunit.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c
+index f76d416881349..0b3dacc7fa424 100644
+--- a/drivers/base/regmap/regmap-kunit.c
++++ b/drivers/base/regmap/regmap-kunit.c
+@@ -58,6 +58,9 @@ static struct regmap *gen_regmap(struct regmap_config *config,
+ int i;
+ struct reg_default *defaults;
+
++ config->disable_locking = config->cache_type == REGCACHE_RBTREE ||
++ config->cache_type == REGCACHE_MAPLE;
++
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+--
+2.39.2
+
--- /dev/null
+From aaa6bf95d77e7345938cf6025740d4df21e69c50 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Jul 2023 15:54:23 +0200
+Subject: s390/mm: fix per vma lock fault handling
+
+From: Sven Schnelle <svens@linux.ibm.com>
+
+[ Upstream commit 7686762d1ed092db4d120e29b565712c969dc075 ]
+
+With per-vma locks, handle_mm_fault() may return non-fatal error
+flags. In this case the code should reset the fault flags before
+returning.
+
+Fixes: e06f47a16573 ("s390/mm: try VMA lock-based page fault handling first")
+Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/mm/fault.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
+index dbe8394234e2b..2f123429a291b 100644
+--- a/arch/s390/mm/fault.c
++++ b/arch/s390/mm/fault.c
+@@ -421,6 +421,8 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access)
+ vma_end_read(vma);
+ if (!(fault & VM_FAULT_RETRY)) {
+ count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
++ if (likely(!(fault & VM_FAULT_ERROR)))
++ fault = 0;
+ goto out;
+ }
+ count_vm_vma_lock_event(VMA_LOCK_RETRY);
+--
+2.39.2
+
drm-amd-move-helper-for-dynamic-speed-switch-check-out-of-smu13.patch
drm-amd-align-smu11-smu_msg_overridepcieparameters-implementation-with-smu13.patch
r8169-revert-2ab19de62d67-r8169-remove-aspm-restrictions-now-that-aspm-is-disabled-during-napi-poll.patch
+jbd2-fix-wrongly-judgement-for-buffer-head-removing-.patch
+kvm-arm64-use-different-pointer-authentication-keys-.patch
+kvm-arm64-handle-kvm_arm_init-failure-correctly-in-f.patch
+blk-mq-fix-stall-due-to-recursive-flush-plug.patch
+powerpc-pseries-vas-hold-mmap_mutex-after-mmap-lock-.patch
+kvm-s390-pv-simplify-shutdown-and-fix-race.patch
+kvm-s390-pv-fix-index-value-of-replaced-asce.patch
+s390-mm-fix-per-vma-lock-fault-handling.patch
+io_uring-don-t-audit-the-capability-check-in-io_urin.patch
+gpio-tps68470-make-tps68470_gpio_output-always-set-t.patch
+gpio-mvebu-make-use-of-devm_pwmchip_add.patch
+gpio-mvebu-fix-irq-domain-leak.patch
+regmap-disable-locking-for-rbtree-and-maple-unit-tes.patch
+btrfs-factor-out-a-btrfs_verify_page-helper.patch
+btrfs-fix-fsverify-read-error-handling-in-end_page_r.patch
+btrfs-fix-race-between-quota-disable-and-relocation.patch
+i2c-delete-error-messages-for-failed-memory-allocati.patch
+i2c-improve-size-determinations.patch
+i2c-nomadik-remove-unnecessary-goto-label.patch
+i2c-nomadik-use-devm_clk_get_enabled.patch
+i2c-nomadik-remove-a-useless-call-in-the-remove-func.patch
+pci-aspm-return-0-or-etimedout-from-pcie_retrain_lin.patch
+pci-aspm-factor-out-pcie_wait_for_retrain.patch
+pci-aspm-avoid-link-retraining-race.patch
+pci-rockchip-remove-writes-to-unused-registers.patch
+pci-rockchip-fix-window-mapping-and-address-translat.patch
+pci-rockchip-don-t-advertise-msi-x-in-pcie-capabilit.patch
+drm-amd-display-convert-delaying-aux-i-disable-to-mo.patch
+drm-amd-display-keep-disable-aux-i-delay-as-0.patch
+drm-amd-display-add-pixel-rate-based-crb-allocation-.patch
+drm-amd-display-fix-dcn315-single-stream-crb-allocat.patch
+drm-amd-display-update-correct-dcn314-register-heade.patch
+drm-amd-display-set-minimum-requirement-for-using-ps.patch
+drm-amd-display-set-minimum-requirement-for-using-ps.patch-31937
+drm-ttm-never-consider-pinned-bos-for-eviction-swap.patch
+maple_tree-add-__init-and-__exit-to-test-module.patch
+maple_tree-fix-32-bit-mas_next-testing.patch
+drm-amd-display-add-fams-validation-before-trying-to.patch
+drm-amd-display-update-extended-blank-for-dcn314-onw.patch
+drm-amd-display-fix-possible-underflow-for-displays-.patch
+drm-amd-display-prevent-vtotal-from-being-set-to-0.patch
+jbd2-remove-t_checkpoint_io_list.patch
+jbd2-remove-journal_clean_one_cp_list.patch
+jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch
+ext4-add-ext4_mb_hint_goal_only-test-in-ext4_mb_use_.patch
+ext4-mballoc-remove-useless-setting-of-ac_criteria.patch
+ext4-fix-rbtree-traversal-bug-in-ext4_mb_use_preallo.patch