--- /dev/null
+From aaaeb1f496a41bc5c232bb302489c1fb47ac214f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 11 Mar 2023 09:11:29 -0500
+Subject: drm/amd/display: Add NULL plane_state check for cursor disable logic
+
+From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+
+[ Upstream commit d29fb7baab09b6a1dc484c9c67933253883e770a ]
+
+[Why]
+While scanning the top_pipe connections we can run into a case where
+the bottom pipe is still connected to a top_pipe but with a NULL
+plane_state.
+
+[How]
+Treat a NULL plane_state the same as the plane being invisible for
+pipe cursor disable logic.
+
+Cc: stable@vger.kernel.org
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Reviewed-by: Charlene Liu <Charlene.Liu@amd.com>
+Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@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/dcn10/dcn10_hw_sequencer.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+index eef6e4c80a37f..73457c32f3e7f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+@@ -3225,7 +3225,9 @@ static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
+ for (test_pipe = pipe_ctx->top_pipe; test_pipe;
+ test_pipe = test_pipe->top_pipe) {
+ // Skip invisible layer and pipe-split plane on same layer
+- if (!test_pipe->plane_state->visible || test_pipe->plane_state->layer_index == cur_layer)
++ if (!test_pipe->plane_state ||
++ !test_pipe->plane_state->visible ||
++ test_pipe->plane_state->layer_index == cur_layer)
+ continue;
+
+ r2 = test_pipe->plane_res.scl_data.recout;
+--
+2.39.2
+
--- /dev/null
+From fd496132ad6ffe4d8bd6b7ee1fcea67a7e21110f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Aug 2021 16:44:37 +0800
+Subject: drm/amd/display: Refine condition of cursor visibility for pipe-split
+
+From: Dale Zhao <dale.zhao@amd.com>
+
+[ Upstream commit 63f8bee439c0e3f94cff90d0f9c7b719be693265 ]
+
+[Why]
+In some scenarios like fullscreen game, major plane is scaled. Then
+if a upper layer owns the cursor, cursor is invisiable in the
+majority of the screen.
+
+[How]
+Instead assuming upper plane handles cursor, summing up upper
+split planes on the same layer. If whole upper plane covers current
+half/whole pipe plane, disable cursor.
+
+Reviewed-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com>
+Acked-by: Mikita Lipski <mikita.lipski@amd.com>
+Signed-off-by: Dale Zhao <dale.zhao@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: d29fb7baab09 ("drm/amd/display: Add NULL plane_state check for cursor disable logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 43 +++++++++++--------
+ 1 file changed, 24 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+index c655d03ef754d..eef6e4c80a37f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+@@ -3211,13 +3211,11 @@ void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data)
+
+ static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
+ {
+- struct pipe_ctx *test_pipe;
++ struct pipe_ctx *test_pipe, *split_pipe;
+ const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data;
+- const struct rect *r1 = &scl_data->recout, *r2;
+- int r1_r = r1->x + r1->width, r1_b = r1->y + r1->height, r2_r, r2_b;
++ struct rect r1 = scl_data->recout, r2, r2_half;
++ int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b;
+ int cur_layer = pipe_ctx->plane_state->layer_index;
+- bool upper_pipe_exists = false;
+- struct fixed31_32 one = dc_fixpt_from_int(1);
+
+ /**
+ * Disable the cursor if there's another pipe above this with a
+@@ -3226,26 +3224,33 @@ static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
+ */
+ for (test_pipe = pipe_ctx->top_pipe; test_pipe;
+ test_pipe = test_pipe->top_pipe) {
+- if (!test_pipe->plane_state->visible)
++ // Skip invisible layer and pipe-split plane on same layer
++ if (!test_pipe->plane_state->visible || test_pipe->plane_state->layer_index == cur_layer)
+ continue;
+
+- r2 = &test_pipe->plane_res.scl_data.recout;
+- r2_r = r2->x + r2->width;
+- r2_b = r2->y + r2->height;
++ r2 = test_pipe->plane_res.scl_data.recout;
++ r2_r = r2.x + r2.width;
++ r2_b = r2.y + r2.height;
++ split_pipe = test_pipe;
+
+- if (r1->x >= r2->x && r1->y >= r2->y && r1_r <= r2_r && r1_b <= r2_b)
+- return true;
++ /**
++ * There is another half plane on same layer because of
++ * pipe-split, merge together per same height.
++ */
++ for (split_pipe = pipe_ctx->top_pipe; split_pipe;
++ split_pipe = split_pipe->top_pipe)
++ if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
++ r2_half = split_pipe->plane_res.scl_data.recout;
++ r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x;
++ r2.width = r2.width + r2_half.width;
++ r2_r = r2.x + r2.width;
++ break;
++ }
+
+- if (test_pipe->plane_state->layer_index < cur_layer)
+- upper_pipe_exists = true;
++ if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b)
++ return true;
+ }
+
+- // if plane scaled, assume an upper plane can handle cursor if it exists.
+- if (upper_pipe_exists &&
+- (scl_data->ratios.horz.value != one.value ||
+- scl_data->ratios.vert.value != one.value))
+- return true;
+-
+ return false;
+ }
+
+--
+2.39.2
+
--- /dev/null
+From 37f0743735931f63d8b34afa9047b159605aa62a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Aug 2022 16:48:56 -0700
+Subject: drm/i915/dg2: Add additional HDMI pixel clock frequencies
+
+From: Taylor, Clinton A <clinton.a.taylor@intel.com>
+
+[ Upstream commit 11c7faa61d136cef92506e4e77d0e6c6e01428bc ]
+
+Using the BSPEC algorithm add addition HDMI pixel clocks to the existing
+table.
+
+v2: remove 297000 unused entry
+
+Cc: Matt Roper <matthew.d.roper@intel.com>
+Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
+Signed-off-by: Taylor, Clinton A <clinton.a.taylor@intel.com>
+Reviewed-by: Balasubramani Vivekanandan <balasubramani.vivekanandan@intel.com>
+[mattrope: Fixed minor whitepsace issue flagged by checkpatch]
+Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220801234856.2832317-1-clinton.a.taylor@intel.com
+Stable-dep-of: d46746b8b13c ("drm/i915/dg2: Add HDMI pixel clock frequencies 267.30 and 319.89 MHz")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/display/intel_snps_phy.c | 1116 +++++++++++++++++
+ 1 file changed, 1116 insertions(+)
+
+diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c
+index 1e6ba0a377265..2030ef0b599f0 100644
+--- a/drivers/gpu/drm/i915/display/intel_snps_phy.c
++++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c
+@@ -583,6 +583,1086 @@ static const struct intel_mpllb_state dg2_hdmi_148_5 = {
+ };
+
+ /* values in the below table are calculted using the algo */
++static const struct intel_mpllb_state dg2_hdmi_25200 = {
++ .clock = 25200,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 5) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 128) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 41943) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 2621),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_27027 = {
++ .clock = 27027,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 5) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 140) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 31876) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 46555),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_28320 = {
++ .clock = 28320,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 5) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 148) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 40894) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 30408),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_30240 = {
++ .clock = 30240,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 5) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 160) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 50331) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 42466),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_31500 = {
++ .clock = 31500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 4) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 68) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 26214),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_36000 = {
++ .clock = 36000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 4) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 82) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 39321) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 39320),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_40000 = {
++ .clock = 40000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 4) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 2),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 96) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 0),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_49500 = {
++ .clock = 49500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 4) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 1),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 126) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 13107) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 13107),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_50000 = {
++ .clock = 50000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 4) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 1),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 128) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 0),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_57284 = {
++ .clock = 57284,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 4) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 150) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 42886) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 49701),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_58000 = {
++ .clock = 58000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 4) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 152) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 52428) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 52427),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_65000 = {
++ .clock = 65000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 72) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 0),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_71000 = {
++ .clock = 71000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 80) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 52428) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 52427),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_74176 = {
++ .clock = 74176,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 22334) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 43829),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_75000 = {
++ .clock = 75000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 88) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 0),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_78750 = {
++ .clock = 78750,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 2),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 94) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 0),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_85500 = {
++ .clock = 85500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 2),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 104) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 26214),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_88750 = {
++ .clock = 88750,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 1),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 110) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 0),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_106500 = {
++ .clock = 106500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 138) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 13107) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 13107),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_108000 = {
++ .clock = 108000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 140) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 26214),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_115500 = {
++ .clock = 115500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 152) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 26214),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_119000 = {
++ .clock = 119000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 3) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 158) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 13107) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 13107),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_135000 = {
++ .clock = 135000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 76) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 0),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_138500 = {
++ .clock = 138500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 78) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 26214),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_147160 = {
++ .clock = 147160,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 84) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 56623) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 6815),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_148352 = {
++ .clock = 148352,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 22334) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 43829),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_154000 = {
++ .clock = 154000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 13) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 2),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 90) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 39321) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 39320),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_162000 = {
++ .clock = 162000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 2),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 96) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 52428) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 52427),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_209800 = {
++ .clock = 209800,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 134) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 60293) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 7864),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_262750 = {
++ .clock = 262750,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 72) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 36044) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 52427),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_268500 = {
++ .clock = 268500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 74) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 45875) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 13107),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_296703 = {
++ .clock = 296703,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 22321) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 36804),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_241500 = {
++ .clock = 241500,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 160) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 39321) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 39320),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_497750 = {
++ .clock = 497750,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 15) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 0),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 166) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 36044) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 52427),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_592000 = {
++ .clock = 592000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 13107) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 13107),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
++static const struct intel_mpllb_state dg2_hdmi_593407 = {
++ .clock = 593407,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 0) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 22328) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 7549),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
+ static const struct intel_mpllb_state dg2_hdmi_297 = {
+ .clock = 297000,
+ .ref_control =
+@@ -649,6 +1729,42 @@ static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
+ &dg2_hdmi_148_5,
+ &dg2_hdmi_297,
+ &dg2_hdmi_594,
++ &dg2_hdmi_25200,
++ &dg2_hdmi_27027,
++ &dg2_hdmi_28320,
++ &dg2_hdmi_30240,
++ &dg2_hdmi_31500,
++ &dg2_hdmi_36000,
++ &dg2_hdmi_40000,
++ &dg2_hdmi_49500,
++ &dg2_hdmi_50000,
++ &dg2_hdmi_57284,
++ &dg2_hdmi_58000,
++ &dg2_hdmi_65000,
++ &dg2_hdmi_71000,
++ &dg2_hdmi_74176,
++ &dg2_hdmi_75000,
++ &dg2_hdmi_78750,
++ &dg2_hdmi_85500,
++ &dg2_hdmi_88750,
++ &dg2_hdmi_106500,
++ &dg2_hdmi_108000,
++ &dg2_hdmi_115500,
++ &dg2_hdmi_119000,
++ &dg2_hdmi_135000,
++ &dg2_hdmi_138500,
++ &dg2_hdmi_147160,
++ &dg2_hdmi_148352,
++ &dg2_hdmi_154000,
++ &dg2_hdmi_162000,
++ &dg2_hdmi_209800,
++ &dg2_hdmi_241500,
++ &dg2_hdmi_262750,
++ &dg2_hdmi_268500,
++ &dg2_hdmi_296703,
++ &dg2_hdmi_497750,
++ &dg2_hdmi_592000,
++ &dg2_hdmi_593407,
+ NULL,
+ };
+
+--
+2.39.2
+
--- /dev/null
+From dde85629344dc14f02b8de7e9574745e00538403 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Feb 2023 10:06:19 +0530
+Subject: drm/i915/dg2: Add HDMI pixel clock frequencies 267.30 and 319.89 MHz
+
+From: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
+
+[ Upstream commit d46746b8b13cbd377ffc733e465d25800459a31b ]
+
+Add snps phy table values for HDMI pixel clocks 267.30 MHz and
+319.89 MHz. Values are based on the Bspec algorithm for
+PLL programming for HDMI.
+
+Cc: stable@vger.kernel.org
+Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/8008
+Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
+Reviewed-by: Uma Shankar <uma.shankar@intel.com>
+Signed-off-by: Uma Shankar <uma.shankar@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20230223043619.3941382-1-ankit.k.nautiyal@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/display/intel_snps_phy.c | 62 +++++++++++++++++++
+ 1 file changed, 62 insertions(+)
+
+diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c
+index 2030ef0b599f0..170690fc735b5 100644
+--- a/drivers/gpu/drm/i915/display/intel_snps_phy.c
++++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c
+@@ -1483,6 +1483,36 @@ static const struct intel_mpllb_state dg2_hdmi_262750 = {
+ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+ };
+
++static const struct intel_mpllb_state dg2_hdmi_267300 = {
++ .clock = 267300,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 7) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 74) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 30146) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 36699),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
+ static const struct intel_mpllb_state dg2_hdmi_268500 = {
+ .clock = 268500,
+ .ref_control =
+@@ -1573,6 +1603,36 @@ static const struct intel_mpllb_state dg2_hdmi_241500 = {
+ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+ };
+
++static const struct intel_mpllb_state dg2_hdmi_319890 = {
++ .clock = 319890,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 2),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 94) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 64094) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 13631),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
+ static const struct intel_mpllb_state dg2_hdmi_497750 = {
+ .clock = 497750,
+ .ref_control =
+@@ -1760,8 +1820,10 @@ static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
+ &dg2_hdmi_209800,
+ &dg2_hdmi_241500,
+ &dg2_hdmi_262750,
++ &dg2_hdmi_267300,
+ &dg2_hdmi_268500,
+ &dg2_hdmi_296703,
++ &dg2_hdmi_319890,
+ &dg2_hdmi_497750,
+ &dg2_hdmi_592000,
+ &dg2_hdmi_593407,
+--
+2.39.2
+
--- /dev/null
+From a2c357aa377de55ac7e5a6eb0b75fb713513b951 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 May 2022 13:34:01 +0530
+Subject: drm/i915/dg2: Support 4k@30 on HDMI
+
+From: Vandita Kulkarni <vandita.kulkarni@intel.com>
+
+[ Upstream commit edd34368c4c3b45b1386b15f78b2229420f8c6d4 ]
+
+This patch adds a fix to support 297MHz of dot clock by calculating
+the pll values using synopsis algorithm.
+This will help to support 4k@30 mode for HDMI monitors on DG2.
+
+v2: As per the algorithm, set MPLLB VCO range control bits to 3,
+in register SNPS_PHY_MPLLB_DIV for 297Mhz. (Matt)
+
+v3: Fix typo. (Ankit)
+
+Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com>
+Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220525080401.1253511-1-ankit.k.nautiyal@intel.com
+Stable-dep-of: d46746b8b13c ("drm/i915/dg2: Add HDMI pixel clock frequencies 267.30 and 319.89 MHz")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/display/intel_snps_phy.c | 32 +++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c
+index 536b319ffe5ba..1e6ba0a377265 100644
+--- a/drivers/gpu/drm/i915/display/intel_snps_phy.c
++++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c
+@@ -582,6 +582,37 @@ static const struct intel_mpllb_state dg2_hdmi_148_5 = {
+ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
+ };
+
++/* values in the below table are calculted using the algo */
++static const struct intel_mpllb_state dg2_hdmi_297 = {
++ .clock = 297000,
++ .ref_control =
++ REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, 3),
++ .mpllb_cp =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, 6) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, 14) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, 64) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, 124),
++ .mpllb_div =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, 2) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, 3),
++ .mpllb_div2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, 86) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, 1),
++ .mpllb_fracn1 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, 1) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, 65535),
++ .mpllb_fracn2 =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, 26214) |
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, 26214),
++ .mpllb_sscen =
++ REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, 1),
++};
++
+ static const struct intel_mpllb_state dg2_hdmi_594 = {
+ .clock = 594000,
+ .ref_control =
+@@ -616,6 +647,7 @@ static const struct intel_mpllb_state *dg2_hdmi_tables[] = {
+ &dg2_hdmi_27_0,
+ &dg2_hdmi_74_25,
+ &dg2_hdmi_148_5,
++ &dg2_hdmi_297,
+ &dg2_hdmi_594,
+ NULL,
+ };
+--
+2.39.2
+
--- /dev/null
+From 854bbaeef7c21e7ac7894cccf342c41245ffebfc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Mar 2023 17:48:05 +0100
+Subject: drm/msm/adreno: fix runtime PM imbalance at gpu load
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit 0d997f95b70f98987ae031a89677c13e0e223670 ]
+
+A recent commit moved enabling of runtime PM to GPU load time (first
+open()) but failed to update the error paths so that runtime PM is
+disabled if initialisation of the GPU fails. This would trigger a
+warning about the unbalanced disable count on the next open() attempt.
+
+Note that pm_runtime_put_noidle() is sufficient to balance the usage
+count when pm_runtime_put_sync() fails (and is chosen over
+pm_runtime_resume_and_get() for consistency reasons).
+
+Fixes: 4b18299b3365 ("drm/msm/adreno: Defer enabling runpm until hw_init()")
+Cc: stable@vger.kernel.org # 6.0
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Patchwork: https://patchwork.freedesktop.org/patch/524971/
+Link: https://lore.kernel.org/r/20230303164807.13124-3-johan+linaro@kernel.org
+Signed-off-by: Rob Clark <robdclark@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/adreno/adreno_device.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
+index afdfa9edbea3d..7c3d80e78fb8b 100644
+--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
++++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
+@@ -406,20 +406,21 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+- pm_runtime_put_sync(&pdev->dev);
++ pm_runtime_put_noidle(&pdev->dev);
+ DRM_DEV_ERROR(dev->dev, "Couldn't power up the GPU: %d\n", ret);
+- return NULL;
++ goto err_disable_rpm;
+ }
+
+ mutex_lock(&gpu->lock);
+ ret = msm_gpu_hw_init(gpu);
+ mutex_unlock(&gpu->lock);
+- pm_runtime_put_autosuspend(&pdev->dev);
+ if (ret) {
+ DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret);
+- return NULL;
++ goto err_put_rpm;
+ }
+
++ pm_runtime_put_autosuspend(&pdev->dev);
++
+ #ifdef CONFIG_DEBUG_FS
+ if (gpu->funcs->debugfs_init) {
+ gpu->funcs->debugfs_init(gpu, dev->primary);
+@@ -428,6 +429,13 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
+ #endif
+
+ return gpu;
++
++err_put_rpm:
++ pm_runtime_put_sync(&pdev->dev);
++err_disable_rpm:
++ pm_runtime_disable(&pdev->dev);
++
++ return NULL;
+ }
+
+ static void set_gpu_pdev(struct drm_device *dev,
+--
+2.39.2
+
--- /dev/null
+From 23803255296607d4300e3f257062071bda6cfb9d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Nov 2021 10:11:03 -0800
+Subject: drm/msm: Remove struct_mutex usage
+
+From: Rob Clark <robdclark@chromium.org>
+
+[ Upstream commit c28e2f2b417ed747bfbc5f900c87f3ec9cc6b25e ]
+
+The remaining struct_mutex usage is just to serialize various gpu
+related things (submit/retire/recover/fault/etc), so replace
+struct_mutex with gpu->lock.
+
+Signed-off-by: Rob Clark <robdclark@chromium.org>
+Link: https://lore.kernel.org/r/20211109181117.591148-4-robdclark@gmail.com
+Signed-off-by: Rob Clark <robdclark@chromium.org>
+Stable-dep-of: 0d997f95b70f ("drm/msm/adreno: fix runtime PM imbalance at gpu load")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/adreno/a5xx_debugfs.c | 4 ++--
+ drivers/gpu/drm/msm/adreno/adreno_device.c | 4 ++--
+ drivers/gpu/drm/msm/msm_debugfs.c | 12 ++++++------
+ drivers/gpu/drm/msm/msm_gpu.c | 14 +++++++-------
+ drivers/gpu/drm/msm/msm_gpu.h | 20 +++++++++++++++-----
+ drivers/gpu/drm/msm/msm_perf.c | 9 ++++++---
+ drivers/gpu/drm/msm/msm_rd.c | 16 +++++++++-------
+ drivers/gpu/drm/msm/msm_ringbuffer.c | 4 ++--
+ 8 files changed, 49 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
+index c9d11d57aed66..1aa39aa73e745 100644
+--- a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
++++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
+@@ -107,7 +107,7 @@ reset_set(void *data, u64 val)
+ * try to reset an active GPU.
+ */
+
+- mutex_lock(&dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+
+ release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
+ adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
+@@ -133,7 +133,7 @@ reset_set(void *data, u64 val)
+ gpu->funcs->recover(gpu);
+
+ pm_runtime_put_sync(&gpu->pdev->dev);
+- mutex_unlock(&dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+
+ return 0;
+ }
+diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
+index 3eb9146653444..afdfa9edbea3d 100644
+--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
++++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
+@@ -411,9 +411,9 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
+ return NULL;
+ }
+
+- mutex_lock(&dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+ ret = msm_gpu_hw_init(gpu);
+- mutex_unlock(&dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+ pm_runtime_put_autosuspend(&pdev->dev);
+ if (ret) {
+ DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret);
+diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
+index dee13fedee3b5..f970a14b66336 100644
+--- a/drivers/gpu/drm/msm/msm_debugfs.c
++++ b/drivers/gpu/drm/msm/msm_debugfs.c
+@@ -29,14 +29,14 @@ static int msm_gpu_show(struct seq_file *m, void *arg)
+ struct msm_gpu *gpu = priv->gpu;
+ int ret;
+
+- ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex);
++ ret = mutex_lock_interruptible(&gpu->lock);
+ if (ret)
+ return ret;
+
+ drm_printf(&p, "%s Status:\n", gpu->name);
+ gpu->funcs->show(gpu, show_priv->state, &p);
+
+- mutex_unlock(&show_priv->dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+
+ return 0;
+ }
+@@ -48,9 +48,9 @@ static int msm_gpu_release(struct inode *inode, struct file *file)
+ struct msm_drm_private *priv = show_priv->dev->dev_private;
+ struct msm_gpu *gpu = priv->gpu;
+
+- mutex_lock(&show_priv->dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+ gpu->funcs->gpu_state_put(show_priv->state);
+- mutex_unlock(&show_priv->dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+
+ kfree(show_priv);
+
+@@ -72,7 +72,7 @@ static int msm_gpu_open(struct inode *inode, struct file *file)
+ if (!show_priv)
+ return -ENOMEM;
+
+- ret = mutex_lock_interruptible(&dev->struct_mutex);
++ ret = mutex_lock_interruptible(&gpu->lock);
+ if (ret)
+ goto free_priv;
+
+@@ -81,7 +81,7 @@ static int msm_gpu_open(struct inode *inode, struct file *file)
+ show_priv->state = gpu->funcs->gpu_state_get(gpu);
+ pm_runtime_put_sync(&gpu->pdev->dev);
+
+- mutex_unlock(&dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+
+ if (IS_ERR(show_priv->state)) {
+ ret = PTR_ERR(show_priv->state);
+diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
+index b01d0a521c908..a2f21b89d077c 100644
+--- a/drivers/gpu/drm/msm/msm_gpu.c
++++ b/drivers/gpu/drm/msm/msm_gpu.c
+@@ -150,7 +150,7 @@ int msm_gpu_hw_init(struct msm_gpu *gpu)
+ {
+ int ret;
+
+- WARN_ON(!mutex_is_locked(&gpu->dev->struct_mutex));
++ WARN_ON(!mutex_is_locked(&gpu->lock));
+
+ if (!gpu->needs_hw_init)
+ return 0;
+@@ -361,7 +361,7 @@ static void recover_worker(struct kthread_work *work)
+ char *comm = NULL, *cmd = NULL;
+ int i;
+
+- mutex_lock(&dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+
+ DRM_DEV_ERROR(dev->dev, "%s: hangcheck recover!\n", gpu->name);
+
+@@ -442,7 +442,7 @@ static void recover_worker(struct kthread_work *work)
+ }
+ }
+
+- mutex_unlock(&dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+
+ msm_gpu_retire(gpu);
+ }
+@@ -450,12 +450,11 @@ static void recover_worker(struct kthread_work *work)
+ static void fault_worker(struct kthread_work *work)
+ {
+ struct msm_gpu *gpu = container_of(work, struct msm_gpu, fault_work);
+- struct drm_device *dev = gpu->dev;
+ struct msm_gem_submit *submit;
+ struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu);
+ char *comm = NULL, *cmd = NULL;
+
+- mutex_lock(&dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+
+ submit = find_submit(cur_ring, cur_ring->memptrs->fence + 1);
+ if (submit && submit->fault_dumped)
+@@ -490,7 +489,7 @@ static void fault_worker(struct kthread_work *work)
+ memset(&gpu->fault_info, 0, sizeof(gpu->fault_info));
+ gpu->aspace->mmu->funcs->resume_translation(gpu->aspace->mmu);
+
+- mutex_unlock(&dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+ }
+
+ static void hangcheck_timer_reset(struct msm_gpu *gpu)
+@@ -734,7 +733,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
+ struct msm_ringbuffer *ring = submit->ring;
+ unsigned long flags;
+
+- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
++ WARN_ON(!mutex_is_locked(&gpu->lock));
+
+ pm_runtime_get_sync(&gpu->pdev->dev);
+
+@@ -849,6 +848,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
+
+ INIT_LIST_HEAD(&gpu->active_list);
+ mutex_init(&gpu->active_lock);
++ mutex_init(&gpu->lock);
+ kthread_init_work(&gpu->retire_work, retire_worker);
+ kthread_init_work(&gpu->recover_work, recover_worker);
+ kthread_init_work(&gpu->fault_work, fault_worker);
+diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
+index 2e2424066e701..461ff5a5aa5bb 100644
+--- a/drivers/gpu/drm/msm/msm_gpu.h
++++ b/drivers/gpu/drm/msm/msm_gpu.h
+@@ -143,13 +143,23 @@ struct msm_gpu {
+ */
+ struct list_head active_list;
+
++ /**
++ * lock:
++ *
++ * General lock for serializing all the gpu things.
++ *
++ * TODO move to per-ring locking where feasible (ie. submit/retire
++ * path, etc)
++ */
++ struct mutex lock;
++
+ /**
+ * active_submits:
+ *
+ * The number of submitted but not yet retired submits, used to
+ * determine transitions between active and idle.
+ *
+- * Protected by lock
++ * Protected by active_lock
+ */
+ int active_submits;
+
+@@ -530,28 +540,28 @@ static inline struct msm_gpu_state *msm_gpu_crashstate_get(struct msm_gpu *gpu)
+ {
+ struct msm_gpu_state *state = NULL;
+
+- mutex_lock(&gpu->dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+
+ if (gpu->crashstate) {
+ kref_get(&gpu->crashstate->ref);
+ state = gpu->crashstate;
+ }
+
+- mutex_unlock(&gpu->dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+
+ return state;
+ }
+
+ static inline void msm_gpu_crashstate_put(struct msm_gpu *gpu)
+ {
+- mutex_lock(&gpu->dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+
+ if (gpu->crashstate) {
+ if (gpu->funcs->gpu_state_put(gpu->crashstate))
+ gpu->crashstate = NULL;
+ }
+
+- mutex_unlock(&gpu->dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+ }
+
+ /*
+diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c
+index 3a27153eef084..3d3da79fec2aa 100644
+--- a/drivers/gpu/drm/msm/msm_perf.c
++++ b/drivers/gpu/drm/msm/msm_perf.c
+@@ -155,9 +155,12 @@ static int perf_open(struct inode *inode, struct file *file)
+ struct msm_gpu *gpu = priv->gpu;
+ int ret = 0;
+
+- mutex_lock(&dev->struct_mutex);
++ if (!gpu)
++ return -ENODEV;
+
+- if (perf->open || !gpu) {
++ mutex_lock(&gpu->lock);
++
++ if (perf->open) {
+ ret = -EBUSY;
+ goto out;
+ }
+@@ -171,7 +174,7 @@ static int perf_open(struct inode *inode, struct file *file)
+ perf->next_jiffies = jiffies + SAMPLE_TIME;
+
+ out:
+- mutex_unlock(&dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+ return ret;
+ }
+
+diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c
+index e3f0dd4a36792..15a44491a42c3 100644
+--- a/drivers/gpu/drm/msm/msm_rd.c
++++ b/drivers/gpu/drm/msm/msm_rd.c
+@@ -86,7 +86,7 @@ struct msm_rd_state {
+ struct msm_gem_submit *submit;
+
+ /* fifo access is synchronized on the producer side by
+- * struct_mutex held by submit code (otherwise we could
++ * gpu->lock held by submit code (otherwise we could
+ * end up w/ cmds logged in different order than they
+ * were executed). And read_lock synchronizes the reads
+ */
+@@ -181,9 +181,12 @@ static int rd_open(struct inode *inode, struct file *file)
+ uint32_t gpu_id;
+ int ret = 0;
+
+- mutex_lock(&dev->struct_mutex);
++ if (!gpu)
++ return -ENODEV;
+
+- if (rd->open || !gpu) {
++ mutex_lock(&gpu->lock);
++
++ if (rd->open) {
+ ret = -EBUSY;
+ goto out;
+ }
+@@ -203,7 +206,7 @@ static int rd_open(struct inode *inode, struct file *file)
+ rd_write_section(rd, RD_GPU_ID, &gpu_id, sizeof(gpu_id));
+
+ out:
+- mutex_unlock(&dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+ return ret;
+ }
+
+@@ -343,11 +346,10 @@ static void snapshot_buf(struct msm_rd_state *rd,
+ msm_gem_unlock(&obj->base);
+ }
+
+-/* called under struct_mutex */
++/* called under gpu->lock */
+ void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
+ const char *fmt, ...)
+ {
+- struct drm_device *dev = submit->dev;
+ struct task_struct *task;
+ char msg[256];
+ int i, n;
+@@ -358,7 +360,7 @@ void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
+ /* writing into fifo is serialized by caller, and
+ * rd->read_lock is used to serialize the reads
+ */
+- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
++ WARN_ON(!mutex_is_locked(&submit->gpu->lock));
+
+ if (fmt) {
+ va_list args;
+diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
+index bd54c14126497..a2314b75962fd 100644
+--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
++++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
+@@ -32,11 +32,11 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job)
+ pm_runtime_get_sync(&gpu->pdev->dev);
+
+ /* TODO move submit path over to using a per-ring lock.. */
+- mutex_lock(&gpu->dev->struct_mutex);
++ mutex_lock(&gpu->lock);
+
+ msm_gpu_submit(gpu, submit);
+
+- mutex_unlock(&gpu->dev->struct_mutex);
++ mutex_unlock(&gpu->lock);
+
+ pm_runtime_put(&gpu->pdev->dev);
+
+--
+2.39.2
+
--- /dev/null
+From 7584fe5f147216d18ccb3b13f90cdeaad6cd6ecd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Jul 2022 10:15:57 +0900
+Subject: ksmbd: add channel rwlock
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 8e06b31e348107c5d78e2c90bb7e69388cb97fb6 ]
+
+Add missing rwlock for channel list in session.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 7b4323373d84 ("ksmbd: fix deadlock in ksmbd_find_crypto_ctx()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/mgmt/user_session.c | 3 +++
+ fs/ksmbd/mgmt/user_session.h | 1 +
+ fs/ksmbd/smb2pdu.c | 20 ++++++++++++++++++--
+ 3 files changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c
+index 8fe08df668582..0c7b5335c12af 100644
+--- a/fs/ksmbd/mgmt/user_session.c
++++ b/fs/ksmbd/mgmt/user_session.c
+@@ -32,11 +32,13 @@ static void free_channel_list(struct ksmbd_session *sess)
+ {
+ struct channel *chann, *tmp;
+
++ write_lock(&sess->chann_lock);
+ list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
+ chann_list) {
+ list_del(&chann->chann_list);
+ kfree(chann);
+ }
++ write_unlock(&sess->chann_lock);
+ }
+
+ static void __session_rpc_close(struct ksmbd_session *sess,
+@@ -305,6 +307,7 @@ static struct ksmbd_session *__session_create(int protocol)
+ INIT_LIST_HEAD(&sess->rpc_handle_list);
+ sess->sequence_number = 1;
+ atomic_set(&sess->refcnt, 1);
++ rwlock_init(&sess->chann_lock);
+
+ switch (protocol) {
+ case CIFDS_SESSION_FLAG_SMB2:
+diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h
+index 8b08189be3fc2..1ec659f0151bf 100644
+--- a/fs/ksmbd/mgmt/user_session.h
++++ b/fs/ksmbd/mgmt/user_session.h
+@@ -48,6 +48,7 @@ struct ksmbd_session {
+ char sess_key[CIFS_KEY_SIZE];
+
+ struct hlist_node hlist;
++ rwlock_t chann_lock;
+ struct list_head ksmbd_chann_list;
+ struct xarray tree_conns;
+ struct ida tree_conn_ida;
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index d41995f89befe..e17f7a5dd9974 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -1525,7 +1525,9 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+
+ binding_session:
+ if (conn->dialect >= SMB30_PROT_ID) {
++ read_lock(&sess->chann_lock);
+ chann = lookup_chann_list(sess, conn);
++ read_unlock(&sess->chann_lock);
+ if (!chann) {
+ chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
+ if (!chann)
+@@ -1533,7 +1535,9 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+
+ chann->conn = conn;
+ INIT_LIST_HEAD(&chann->chann_list);
++ write_lock(&sess->chann_lock);
+ list_add(&chann->chann_list, &sess->ksmbd_chann_list);
++ write_unlock(&sess->chann_lock);
+ }
+ }
+
+@@ -1608,7 +1612,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
+ }
+
+ if (conn->dialect >= SMB30_PROT_ID) {
++ read_lock(&sess->chann_lock);
+ chann = lookup_chann_list(sess, conn);
++ read_unlock(&sess->chann_lock);
+ if (!chann) {
+ chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
+ if (!chann)
+@@ -1616,7 +1622,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
+
+ chann->conn = conn;
+ INIT_LIST_HEAD(&chann->chann_list);
++ write_lock(&sess->chann_lock);
+ list_add(&chann->chann_list, &sess->ksmbd_chann_list);
++ write_unlock(&sess->chann_lock);
+ }
+ }
+
+@@ -8388,10 +8396,14 @@ int smb3_check_sign_req(struct ksmbd_work *work)
+ if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
+ signing_key = work->sess->smb3signingkey;
+ } else {
++ read_lock(&work->sess->chann_lock);
+ chann = lookup_chann_list(work->sess, conn);
+- if (!chann)
++ if (!chann) {
++ read_unlock(&work->sess->chann_lock);
+ return 0;
++ }
+ signing_key = chann->smb3signingkey;
++ read_unlock(&work->sess->chann_lock);
+ }
+
+ if (!signing_key) {
+@@ -8451,10 +8463,14 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
+ le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
+ signing_key = work->sess->smb3signingkey;
+ } else {
++ read_lock(&work->sess->chann_lock);
+ chann = lookup_chann_list(work->sess, work->conn);
+- if (!chann)
++ if (!chann) {
++ read_unlock(&work->sess->chann_lock);
+ return;
++ }
+ signing_key = chann->smb3signingkey;
++ read_unlock(&work->sess->chann_lock);
+ }
+
+ if (!signing_key)
+--
+2.39.2
+
--- /dev/null
+From d1aed81d3f634902eb47a032a4579d5a78b29b1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 May 2023 08:44:14 +0900
+Subject: ksmbd: fix deadlock in ksmbd_find_crypto_ctx()
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 7b4323373d844954bb76e0e9f39c4e5fc785fa7b ]
+
+Deadlock is triggered by sending multiple concurrent session setup
+requests. It should be reused after releasing when getting ctx for crypto.
+Multiple consecutive ctx uses cause deadlock while waiting for releasing
+due to the limited number of ctx.
+
+Cc: stable@vger.kernel.org
+Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20591
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/auth.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c
+index c1408e922fc6b..59d2059467465 100644
+--- a/fs/ksmbd/auth.c
++++ b/fs/ksmbd/auth.c
+@@ -220,22 +220,22 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ {
+ char ntlmv2_hash[CIFS_ENCPWD_SIZE];
+ char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
+- struct ksmbd_crypto_ctx *ctx;
++ struct ksmbd_crypto_ctx *ctx = NULL;
+ char *construct = NULL;
+ int rc, len;
+
+- ctx = ksmbd_crypto_ctx_find_hmacmd5();
+- if (!ctx) {
+- ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
+- return -ENOMEM;
+- }
+-
+ rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
+ if (rc) {
+ ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
+ goto out;
+ }
+
++ ctx = ksmbd_crypto_ctx_find_hmacmd5();
++ if (!ctx) {
++ ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
++ return -ENOMEM;
++ }
++
+ rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx),
+ ntlmv2_hash,
+ CIFS_HMAC_MD5_HASH_SIZE);
+@@ -271,6 +271,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ ksmbd_debug(AUTH, "Could not generate md5 hash\n");
+ goto out;
+ }
++ ksmbd_release_crypto_ctx(ctx);
++ ctx = NULL;
+
+ rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp);
+ if (rc) {
+@@ -281,7 +283,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
+ if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0)
+ rc = -EINVAL;
+ out:
+- ksmbd_release_crypto_ctx(ctx);
++ if (ctx)
++ ksmbd_release_crypto_ctx(ctx);
+ kfree(construct);
+ return rc;
+ }
+--
+2.39.2
+
--- /dev/null
+From e422c48bc373790c7a99f05459d85a5335552b26 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Jul 2022 10:17:06 +0900
+Subject: ksmbd: fix kernel oops from idr_remove()
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 17ea92a9f6d0b9a97aaec5ab748e4591d70a562c ]
+
+There is a report that kernel oops happen from idr_remove().
+
+kernel: BUG: kernel NULL pointer dereference, address: 0000000000000010
+kernel: RIP: 0010:idr_remove+0x1/0x20
+kernel: __ksmbd_close_fd+0xb2/0x2d0 [ksmbd]
+kernel: ksmbd_vfs_read+0x91/0x190 [ksmbd]
+kernel: ksmbd_fd_put+0x29/0x40 [ksmbd]
+kernel: smb2_read+0x210/0x390 [ksmbd]
+kernel: __process_request+0xa4/0x180 [ksmbd]
+kernel: __handle_ksmbd_work+0xf0/0x290 [ksmbd]
+kernel: handle_ksmbd_work+0x2d/0x50 [ksmbd]
+kernel: process_one_work+0x21d/0x3f0
+kernel: worker_thread+0x50/0x3d0
+kernel: rescuer_thread+0x390/0x390
+kernel: kthread+0xee/0x120
+kthread_complete_and_exit+0x20/0x20
+kernel: ret_from_fork+0x22/0x30
+
+While accessing files, If connection is disconnected, windows send
+session setup request included previous session destroy. But while still
+processing requests on previous session, this request destroy file
+table, which mean file table idr will be freed and set to NULL.
+So kernel oops happen from ft->idr in __ksmbd_close_fd().
+This patch don't directly destroy session in destroy_previous_session().
+It just set to KSMBD_SESS_EXITING so that connection will be
+terminated after finishing the rest of requests.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 7b4323373d84 ("ksmbd: fix deadlock in ksmbd_find_crypto_ctx()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/mgmt/user_session.c | 2 ++
+ fs/ksmbd/smb2pdu.c | 8 ++++++--
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c
+index 0c7b5335c12af..9c4a9c8c02795 100644
+--- a/fs/ksmbd/mgmt/user_session.c
++++ b/fs/ksmbd/mgmt/user_session.c
+@@ -241,6 +241,8 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
+ sess = ksmbd_session_lookup(conn, id);
+ if (!sess && conn->binding)
+ sess = ksmbd_session_lookup_slowpath(id);
++ if (sess && sess->state != SMB2_SESSION_VALID)
++ sess = NULL;
+ return sess;
+ }
+
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index e17f7a5dd9974..8bfe2a6c05f92 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -600,6 +600,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
+ {
+ struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
+ struct ksmbd_user *prev_user;
++ struct channel *chann;
+
+ if (!prev_sess)
+ return;
+@@ -615,8 +616,11 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
+ }
+
+ put_session(prev_sess);
+- xa_erase(&conn->sessions, prev_sess->id);
+- ksmbd_session_destroy(prev_sess);
++ prev_sess->state = SMB2_SESSION_EXPIRED;
++ write_lock(&prev_sess->chann_lock);
++ list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
++ chann->conn->status = KSMBD_SESS_EXITING;
++ write_unlock(&prev_sess->chann_lock);
+ }
+
+ /**
+--
+2.39.2
+
--- /dev/null
+From a8bbd42d76ead12063d0340271c6043606a71c05 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Dec 2021 14:57:27 +0900
+Subject: ksmbd: fix multi session connection failure
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit ce53d365378cde71bb6596d79c257e600d951d29 ]
+
+When RSS mode is enable, windows client do simultaneously send several
+session requests to server. There is racy issue using
+sess->ntlmssp.cryptkey on N connection : 1 session. So authetication
+failed using wrong cryptkey on some session. This patch move cryptkey
+to ksmbd_conn structure to use each cryptkey on connection.
+
+Tested-by: Ziwei Xie <zw.xie@high-flyer.cn>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 7b4323373d84 ("ksmbd: fix deadlock in ksmbd_find_crypto_ctx()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/auth.c | 27 ++++++++++++++-------------
+ fs/ksmbd/auth.h | 10 +++++-----
+ fs/ksmbd/connection.h | 7 +------
+ fs/ksmbd/mgmt/user_session.h | 1 -
+ fs/ksmbd/smb2pdu.c | 8 ++++----
+ 5 files changed, 24 insertions(+), 29 deletions(-)
+
+diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c
+index b962b16e5aeb7..4867da417c23a 100644
+--- a/fs/ksmbd/auth.c
++++ b/fs/ksmbd/auth.c
+@@ -215,7 +215,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
+ * Return: 0 on success, error number on error
+ */
+ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
+- int blen, char *domain_name)
++ int blen, char *domain_name, char *cryptkey)
+ {
+ char ntlmv2_hash[CIFS_ENCPWD_SIZE];
+ char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
+@@ -256,7 +256,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
+ goto out;
+ }
+
+- memcpy(construct, sess->ntlmssp.cryptkey, CIFS_CRYPTO_KEY_SIZE);
++ memcpy(construct, cryptkey, CIFS_CRYPTO_KEY_SIZE);
+ memcpy(construct + CIFS_CRYPTO_KEY_SIZE, &ntlmv2->blob_signature, blen);
+
+ rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), construct, len);
+@@ -295,7 +295,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
+ * Return: 0 on success, error number on error
+ */
+ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
+- int blob_len, struct ksmbd_session *sess)
++ int blob_len, struct ksmbd_conn *conn,
++ struct ksmbd_session *sess)
+ {
+ char *domain_name;
+ unsigned int nt_off, dn_off;
+@@ -325,7 +326,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
+
+ /* TODO : use domain name that imported from configuration file */
+ domain_name = smb_strndup_from_utf16((const char *)authblob + dn_off,
+- dn_len, true, sess->conn->local_nls);
++ dn_len, true, conn->local_nls);
+ if (IS_ERR(domain_name))
+ return PTR_ERR(domain_name);
+
+@@ -334,7 +335,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
+ domain_name);
+ ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off),
+ nt_len - CIFS_ENCPWD_SIZE,
+- domain_name);
++ domain_name, conn->ntlmssp.cryptkey);
+ kfree(domain_name);
+ return ret;
+ }
+@@ -348,7 +349,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
+ *
+ */
+ int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
+- int blob_len, struct ksmbd_session *sess)
++ int blob_len, struct ksmbd_conn *conn)
+ {
+ if (blob_len < sizeof(struct negotiate_message)) {
+ ksmbd_debug(AUTH, "negotiate blob len %d too small\n",
+@@ -362,7 +363,7 @@ int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
+ return -EINVAL;
+ }
+
+- sess->ntlmssp.client_flags = le32_to_cpu(negblob->NegotiateFlags);
++ conn->ntlmssp.client_flags = le32_to_cpu(negblob->NegotiateFlags);
+ return 0;
+ }
+
+@@ -376,14 +377,14 @@ int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
+ */
+ unsigned int
+ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
+- struct ksmbd_session *sess)
++ struct ksmbd_conn *conn)
+ {
+ struct target_info *tinfo;
+ wchar_t *name;
+ __u8 *target_name;
+ unsigned int flags, blob_off, blob_len, type, target_info_len = 0;
+ int len, uni_len, conv_len;
+- int cflags = sess->ntlmssp.client_flags;
++ int cflags = conn->ntlmssp.client_flags;
+
+ memcpy(chgblob->Signature, NTLMSSP_SIGNATURE, 8);
+ chgblob->MessageType = NtLmChallenge;
+@@ -404,7 +405,7 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
+ if (cflags & NTLMSSP_REQUEST_TARGET)
+ flags |= NTLMSSP_REQUEST_TARGET;
+
+- if (sess->conn->use_spnego &&
++ if (conn->use_spnego &&
+ (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
+ flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC;
+
+@@ -415,7 +416,7 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
+ return -ENOMEM;
+
+ conv_len = smb_strtoUTF16((__le16 *)name, ksmbd_netbios_name(), len,
+- sess->conn->local_nls);
++ conn->local_nls);
+ if (conv_len < 0 || conv_len > len) {
+ kfree(name);
+ return -EINVAL;
+@@ -431,8 +432,8 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
+ chgblob->TargetName.BufferOffset = cpu_to_le32(blob_off);
+
+ /* Initialize random conn challenge */
+- get_random_bytes(sess->ntlmssp.cryptkey, sizeof(__u64));
+- memcpy(chgblob->Challenge, sess->ntlmssp.cryptkey,
++ get_random_bytes(conn->ntlmssp.cryptkey, sizeof(__u64));
++ memcpy(chgblob->Challenge, conn->ntlmssp.cryptkey,
+ CIFS_CRYPTO_KEY_SIZE);
+
+ /* Add Target Information to security buffer */
+diff --git a/fs/ksmbd/auth.h b/fs/ksmbd/auth.h
+index 9c2d4badd05d1..95629651cf266 100644
+--- a/fs/ksmbd/auth.h
++++ b/fs/ksmbd/auth.h
+@@ -38,16 +38,16 @@ struct kvec;
+ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
+ unsigned int nvec, int enc);
+ void ksmbd_copy_gss_neg_header(void *buf);
+-int ksmbd_auth_ntlm(struct ksmbd_session *sess, char *pw_buf);
+ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
+- int blen, char *domain_name);
++ int blen, char *domain_name, char *cryptkey);
+ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
+- int blob_len, struct ksmbd_session *sess);
++ int blob_len, struct ksmbd_conn *conn,
++ struct ksmbd_session *sess);
+ int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
+- int blob_len, struct ksmbd_session *sess);
++ int blob_len, struct ksmbd_conn *conn);
+ unsigned int
+ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
+- struct ksmbd_session *sess);
++ struct ksmbd_conn *conn);
+ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
+ int in_len, char *out_blob, int *out_len);
+ int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
+diff --git a/fs/ksmbd/connection.h b/fs/ksmbd/connection.h
+index 4b15c5e673d92..f3367d7760d7e 100644
+--- a/fs/ksmbd/connection.h
++++ b/fs/ksmbd/connection.h
+@@ -72,12 +72,7 @@ struct ksmbd_conn {
+ int connection_type;
+ struct ksmbd_stats stats;
+ char ClientGUID[SMB2_CLIENT_GUID_SIZE];
+- union {
+- /* pending trans request table */
+- struct trans_state *recent_trans;
+- /* Used by ntlmssp */
+- char *ntlmssp_cryptkey;
+- };
++ struct ntlmssp_auth ntlmssp;
+
+ spinlock_t llist_lock;
+ struct list_head lock_list;
+diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h
+index 82289c3cbd2bc..e241f16a38512 100644
+--- a/fs/ksmbd/mgmt/user_session.h
++++ b/fs/ksmbd/mgmt/user_session.h
+@@ -45,7 +45,6 @@ struct ksmbd_session {
+ int state;
+ __u8 *Preauth_HashValue;
+
+- struct ntlmssp_auth ntlmssp;
+ char sess_key[CIFS_KEY_SIZE];
+
+ struct hlist_node hlist;
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index c8c2b326ee042..bb8126deeaf29 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -1316,7 +1316,7 @@ static int ntlm_negotiate(struct ksmbd_work *work,
+ int sz, rc;
+
+ ksmbd_debug(SMB, "negotiate phase\n");
+- rc = ksmbd_decode_ntlmssp_neg_blob(negblob, negblob_len, work->sess);
++ rc = ksmbd_decode_ntlmssp_neg_blob(negblob, negblob_len, work->conn);
+ if (rc)
+ return rc;
+
+@@ -1326,7 +1326,7 @@ static int ntlm_negotiate(struct ksmbd_work *work,
+ memset(chgblob, 0, sizeof(struct challenge_message));
+
+ if (!work->conn->use_spnego) {
+- sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->sess);
++ sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->conn);
+ if (sz < 0)
+ return -ENOMEM;
+
+@@ -1342,7 +1342,7 @@ static int ntlm_negotiate(struct ksmbd_work *work,
+ return -ENOMEM;
+
+ chgblob = (struct challenge_message *)neg_blob;
+- sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->sess);
++ sz = ksmbd_build_ntlmssp_challenge_blob(chgblob, work->conn);
+ if (sz < 0) {
+ rc = -ENOMEM;
+ goto out;
+@@ -1480,7 +1480,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+
+ authblob = user_authblob(conn, req);
+ sz = le16_to_cpu(req->SecurityBufferLength);
+- rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, sess);
++ rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess);
+ if (rc) {
+ set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD);
+ ksmbd_debug(SMB, "authentication failed\n");
+--
+2.39.2
+
--- /dev/null
+From 07bc60603620513e77b5e4d64a1c0786aa9536fd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Jul 2022 13:36:52 +0900
+Subject: ksmbd: fix racy issue while destroying session on multichannel
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit af7c39d971e43cd0af488729bca362427ad99488 ]
+
+After multi-channel connection with windows, Several channels of
+session are connected. Among them, if there is a problem in one channel,
+Windows connects again after disconnecting the channel. In this process,
+the session is released and a kernel oop can occurs while processing
+requests to other channels. When the channel is disconnected, if other
+channels still exist in the session after deleting the channel from
+the channel list in the session, the session should not be released.
+Finally, the session will be released after all channels are disconnected.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 7b4323373d84 ("ksmbd: fix deadlock in ksmbd_find_crypto_ctx()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/auth.c | 56 ++++++++++++++++--------------
+ fs/ksmbd/auth.h | 11 +++---
+ fs/ksmbd/connection.h | 7 ----
+ fs/ksmbd/mgmt/tree_connect.c | 5 +--
+ fs/ksmbd/mgmt/tree_connect.h | 4 ++-
+ fs/ksmbd/mgmt/user_session.c | 67 ++++++++++++++++++++++++------------
+ fs/ksmbd/mgmt/user_session.h | 7 ++--
+ fs/ksmbd/oplock.c | 11 +++---
+ fs/ksmbd/smb2pdu.c | 21 +++++------
+ fs/ksmbd/smb_common.h | 2 +-
+ fs/ksmbd/vfs.c | 3 +-
+ fs/ksmbd/vfs_cache.c | 2 +-
+ 12 files changed, 110 insertions(+), 86 deletions(-)
+
+diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c
+index 4867da417c23a..c1408e922fc6b 100644
+--- a/fs/ksmbd/auth.c
++++ b/fs/ksmbd/auth.c
+@@ -120,8 +120,8 @@ static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash,
+ return rc;
+ }
+
+-static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
+- char *dname)
++static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
++ char *ntlmv2_hash, char *dname)
+ {
+ int ret, len, conv_len;
+ wchar_t *domain = NULL;
+@@ -157,7 +157,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
+ }
+
+ conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len,
+- sess->conn->local_nls);
++ conn->local_nls);
+ if (conv_len < 0 || conv_len > len) {
+ ret = -EINVAL;
+ goto out;
+@@ -181,7 +181,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
+ }
+
+ conv_len = smb_strtoUTF16((__le16 *)domain, dname, len,
+- sess->conn->local_nls);
++ conn->local_nls);
+ if (conv_len < 0 || conv_len > len) {
+ ret = -EINVAL;
+ goto out;
+@@ -214,8 +214,9 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
+ *
+ * Return: 0 on success, error number on error
+ */
+-int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
+- int blen, char *domain_name, char *cryptkey)
++int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
++ struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
++ char *cryptkey)
+ {
+ char ntlmv2_hash[CIFS_ENCPWD_SIZE];
+ char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
+@@ -229,7 +230,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
+ return -ENOMEM;
+ }
+
+- rc = calc_ntlmv2_hash(sess, ntlmv2_hash, domain_name);
++ rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
+ if (rc) {
+ ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
+ goto out;
+@@ -333,7 +334,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
+ /* process NTLMv2 authentication */
+ ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n",
+ domain_name);
+- ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off),
++ ret = ksmbd_auth_ntlmv2(conn, sess,
++ (struct ntlmv2_resp *)((char *)authblob + nt_off),
+ nt_len - CIFS_ENCPWD_SIZE,
+ domain_name, conn->ntlmssp.cryptkey);
+ kfree(domain_name);
+@@ -633,8 +635,9 @@ struct derivation {
+ bool binding;
+ };
+
+-static int generate_key(struct ksmbd_session *sess, struct kvec label,
+- struct kvec context, __u8 *key, unsigned int key_size)
++static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
++ struct kvec label, struct kvec context, __u8 *key,
++ unsigned int key_size)
+ {
+ unsigned char zero = 0x0;
+ __u8 i[4] = {0, 0, 0, 1};
+@@ -694,8 +697,8 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label,
+ goto smb3signkey_ret;
+ }
+
+- if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
+- sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
++ if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
++ conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
+ rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4);
+ else
+ rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4);
+@@ -730,17 +733,17 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
+ if (!chann)
+ return 0;
+
+- if (sess->conn->dialect >= SMB30_PROT_ID && signing->binding)
++ if (conn->dialect >= SMB30_PROT_ID && signing->binding)
+ key = chann->smb3signingkey;
+ else
+ key = sess->smb3signingkey;
+
+- rc = generate_key(sess, signing->label, signing->context, key,
++ rc = generate_key(conn, sess, signing->label, signing->context, key,
+ SMB3_SIGN_KEY_SIZE);
+ if (rc)
+ return rc;
+
+- if (!(sess->conn->dialect >= SMB30_PROT_ID && signing->binding))
++ if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
+ memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE);
+
+ ksmbd_debug(AUTH, "dumping generated AES signing keys\n");
+@@ -794,30 +797,31 @@ struct derivation_twin {
+ struct derivation decryption;
+ };
+
+-static int generate_smb3encryptionkey(struct ksmbd_session *sess,
++static int generate_smb3encryptionkey(struct ksmbd_conn *conn,
++ struct ksmbd_session *sess,
+ const struct derivation_twin *ptwin)
+ {
+ int rc;
+
+- rc = generate_key(sess, ptwin->encryption.label,
++ rc = generate_key(conn, sess, ptwin->encryption.label,
+ ptwin->encryption.context, sess->smb3encryptionkey,
+ SMB3_ENC_DEC_KEY_SIZE);
+ if (rc)
+ return rc;
+
+- rc = generate_key(sess, ptwin->decryption.label,
++ rc = generate_key(conn, sess, ptwin->decryption.label,
+ ptwin->decryption.context,
+ sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
+ if (rc)
+ return rc;
+
+ ksmbd_debug(AUTH, "dumping generated AES encryption keys\n");
+- ksmbd_debug(AUTH, "Cipher type %d\n", sess->conn->cipher_type);
++ ksmbd_debug(AUTH, "Cipher type %d\n", conn->cipher_type);
+ ksmbd_debug(AUTH, "Session Id %llu\n", sess->id);
+ ksmbd_debug(AUTH, "Session Key %*ph\n",
+ SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
+- if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
+- sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
++ if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
++ conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
+ ksmbd_debug(AUTH, "ServerIn Key %*ph\n",
+ SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey);
+ ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
+@@ -831,7 +835,8 @@ static int generate_smb3encryptionkey(struct ksmbd_session *sess,
+ return 0;
+ }
+
+-int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess)
++int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
++ struct ksmbd_session *sess)
+ {
+ struct derivation_twin twin;
+ struct derivation *d;
+@@ -848,10 +853,11 @@ int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess)
+ d->context.iov_base = "ServerIn ";
+ d->context.iov_len = 10;
+
+- return generate_smb3encryptionkey(sess, &twin);
++ return generate_smb3encryptionkey(conn, sess, &twin);
+ }
+
+-int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess)
++int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
++ struct ksmbd_session *sess)
+ {
+ struct derivation_twin twin;
+ struct derivation *d;
+@@ -868,7 +874,7 @@ int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess)
+ d->context.iov_base = sess->Preauth_HashValue;
+ d->context.iov_len = 64;
+
+- return generate_smb3encryptionkey(sess, &twin);
++ return generate_smb3encryptionkey(conn, sess, &twin);
+ }
+
+ int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
+diff --git a/fs/ksmbd/auth.h b/fs/ksmbd/auth.h
+index 95629651cf266..25b772653de0a 100644
+--- a/fs/ksmbd/auth.h
++++ b/fs/ksmbd/auth.h
+@@ -38,8 +38,9 @@ struct kvec;
+ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
+ unsigned int nvec, int enc);
+ void ksmbd_copy_gss_neg_header(void *buf);
+-int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
+- int blen, char *domain_name, char *cryptkey);
++int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
++ struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
++ char *cryptkey);
+ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
+ int blob_len, struct ksmbd_conn *conn,
+ struct ksmbd_session *sess);
+@@ -58,8 +59,10 @@ int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
+ struct ksmbd_conn *conn);
+ int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
+ struct ksmbd_conn *conn);
+-int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess);
+-int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess);
++int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
++ struct ksmbd_session *sess);
++int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
++ struct ksmbd_session *sess);
+ int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
+ __u8 *pi_hash);
+ int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len,
+diff --git a/fs/ksmbd/connection.h b/fs/ksmbd/connection.h
+index 7838cc46497d6..89eb41bbd1601 100644
+--- a/fs/ksmbd/connection.h
++++ b/fs/ksmbd/connection.h
+@@ -20,13 +20,6 @@
+
+ #define KSMBD_SOCKET_BACKLOG 16
+
+-/*
+- * WARNING
+- *
+- * This is nothing but a HACK. Session status should move to channel
+- * or to session. As of now we have 1 tcp_conn : 1 ksmbd_session, but
+- * we need to change it to 1 tcp_conn : N ksmbd_sessions.
+- */
+ enum {
+ KSMBD_SESS_NEW = 0,
+ KSMBD_SESS_GOOD,
+diff --git a/fs/ksmbd/mgmt/tree_connect.c b/fs/ksmbd/mgmt/tree_connect.c
+index 940385c6a9135..dd262daa2c4a5 100644
+--- a/fs/ksmbd/mgmt/tree_connect.c
++++ b/fs/ksmbd/mgmt/tree_connect.c
+@@ -16,7 +16,8 @@
+ #include "user_session.h"
+
+ struct ksmbd_tree_conn_status
+-ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name)
++ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
++ char *share_name)
+ {
+ struct ksmbd_tree_conn_status status = {-ENOENT, NULL};
+ struct ksmbd_tree_connect_response *resp = NULL;
+@@ -41,7 +42,7 @@ ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name)
+ goto out_error;
+ }
+
+- peer_addr = KSMBD_TCP_PEER_SOCKADDR(sess->conn);
++ peer_addr = KSMBD_TCP_PEER_SOCKADDR(conn);
+ resp = ksmbd_ipc_tree_connect_request(sess,
+ sc,
+ tree_conn,
+diff --git a/fs/ksmbd/mgmt/tree_connect.h b/fs/ksmbd/mgmt/tree_connect.h
+index 18e2a996e0aab..71e50271dccf0 100644
+--- a/fs/ksmbd/mgmt/tree_connect.h
++++ b/fs/ksmbd/mgmt/tree_connect.h
+@@ -12,6 +12,7 @@
+
+ struct ksmbd_share_config;
+ struct ksmbd_user;
++struct ksmbd_conn;
+
+ struct ksmbd_tree_connect {
+ int id;
+@@ -40,7 +41,8 @@ static inline int test_tree_conn_flag(struct ksmbd_tree_connect *tree_conn,
+ struct ksmbd_session;
+
+ struct ksmbd_tree_conn_status
+-ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name);
++ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
++ char *share_name);
+
+ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
+ struct ksmbd_tree_connect *tree_conn);
+diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c
+index 9c4a9c8c02795..92b1603b5abeb 100644
+--- a/fs/ksmbd/mgmt/user_session.c
++++ b/fs/ksmbd/mgmt/user_session.c
+@@ -153,9 +153,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
+ if (!sess)
+ return;
+
+- if (!atomic_dec_and_test(&sess->refcnt))
+- return;
+-
+ down_write(&sessions_table_lock);
+ hash_del(&sess->hlist);
+ up_write(&sessions_table_lock);
+@@ -186,16 +183,58 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
+ int ksmbd_session_register(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess)
+ {
+- sess->conn = conn;
++ sess->dialect = conn->dialect;
++ memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
+ return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
+ }
+
++static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
++{
++ struct channel *chann, *tmp;
++
++ write_lock(&sess->chann_lock);
++ list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
++ chann_list) {
++ if (chann->conn == conn) {
++ list_del(&chann->chann_list);
++ kfree(chann);
++ write_unlock(&sess->chann_lock);
++ return 0;
++ }
++ }
++ write_unlock(&sess->chann_lock);
++
++ return -ENOENT;
++}
++
+ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
+ {
+ struct ksmbd_session *sess;
+- unsigned long id;
+
+- xa_for_each(&conn->sessions, id, sess) {
++ if (conn->binding) {
++ int bkt;
++
++ down_write(&sessions_table_lock);
++ hash_for_each(sessions_table, bkt, sess, hlist) {
++ if (!ksmbd_chann_del(conn, sess)) {
++ up_write(&sessions_table_lock);
++ goto sess_destroy;
++ }
++ }
++ up_write(&sessions_table_lock);
++ } else {
++ unsigned long id;
++
++ xa_for_each(&conn->sessions, id, sess) {
++ if (!ksmbd_chann_del(conn, sess))
++ goto sess_destroy;
++ }
++ }
++
++ return;
++
++sess_destroy:
++ if (list_empty(&sess->ksmbd_chann_list)) {
+ xa_erase(&conn->sessions, sess->id);
+ ksmbd_session_destroy(sess);
+ }
+@@ -207,27 +246,12 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
+ return xa_load(&conn->sessions, id);
+ }
+
+-int get_session(struct ksmbd_session *sess)
+-{
+- return atomic_inc_not_zero(&sess->refcnt);
+-}
+-
+-void put_session(struct ksmbd_session *sess)
+-{
+- if (atomic_dec_and_test(&sess->refcnt))
+- pr_err("get/%s seems to be mismatched.", __func__);
+-}
+-
+ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
+ {
+ struct ksmbd_session *sess;
+
+ down_read(&sessions_table_lock);
+ sess = __session_lookup(id);
+- if (sess) {
+- if (!get_session(sess))
+- sess = NULL;
+- }
+ up_read(&sessions_table_lock);
+
+ return sess;
+@@ -308,7 +332,6 @@ static struct ksmbd_session *__session_create(int protocol)
+ INIT_LIST_HEAD(&sess->ksmbd_chann_list);
+ INIT_LIST_HEAD(&sess->rpc_handle_list);
+ sess->sequence_number = 1;
+- atomic_set(&sess->refcnt, 1);
+ rwlock_init(&sess->chann_lock);
+
+ switch (protocol) {
+diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h
+index 1ec659f0151bf..8934b8ee275ba 100644
+--- a/fs/ksmbd/mgmt/user_session.h
++++ b/fs/ksmbd/mgmt/user_session.h
+@@ -33,8 +33,10 @@ struct preauth_session {
+ struct ksmbd_session {
+ u64 id;
+
++ __u16 dialect;
++ char ClientGUID[SMB2_CLIENT_GUID_SIZE];
++
+ struct ksmbd_user *user;
+- struct ksmbd_conn *conn;
+ unsigned int sequence_number;
+ unsigned int flags;
+
+@@ -59,7 +61,6 @@ struct ksmbd_session {
+ __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
+
+ struct ksmbd_file_table file_table;
+- atomic_t refcnt;
+ };
+
+ static inline int test_session_flag(struct ksmbd_session *sess, int bit)
+@@ -100,6 +101,4 @@ void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id);
+ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name);
+ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id);
+ int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id);
+-int get_session(struct ksmbd_session *sess);
+-void put_session(struct ksmbd_session *sess);
+ #endif /* __USER_SESSION_MANAGEMENT_H__ */
+diff --git a/fs/ksmbd/oplock.c b/fs/ksmbd/oplock.c
+index f9dae6ef21150..3f759f9123ea7 100644
+--- a/fs/ksmbd/oplock.c
++++ b/fs/ksmbd/oplock.c
+@@ -30,6 +30,7 @@ static DEFINE_RWLOCK(lease_list_lock);
+ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
+ u64 id, __u16 Tid)
+ {
++ struct ksmbd_conn *conn = work->conn;
+ struct ksmbd_session *sess = work->sess;
+ struct oplock_info *opinfo;
+
+@@ -38,7 +39,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
+ return NULL;
+
+ opinfo->sess = sess;
+- opinfo->conn = sess->conn;
++ opinfo->conn = conn;
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ opinfo->op_state = OPLOCK_STATE_NONE;
+ opinfo->pending_break = 0;
+@@ -972,7 +973,7 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
+ }
+
+ list_for_each_entry(lb, &lease_table_list, l_entry) {
+- if (!memcmp(lb->client_guid, sess->conn->ClientGUID,
++ if (!memcmp(lb->client_guid, sess->ClientGUID,
+ SMB2_CLIENT_GUID_SIZE))
+ goto found;
+ }
+@@ -988,7 +989,7 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
+ rcu_read_unlock();
+ if (opinfo->o_fp->f_ci == ci)
+ goto op_next;
+- err = compare_guid_key(opinfo, sess->conn->ClientGUID,
++ err = compare_guid_key(opinfo, sess->ClientGUID,
+ lctx->lease_key);
+ if (err) {
+ err = -EINVAL;
+@@ -1122,7 +1123,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
+ struct oplock_info *m_opinfo;
+
+ /* is lease already granted ? */
+- m_opinfo = same_client_has_lease(ci, sess->conn->ClientGUID,
++ m_opinfo = same_client_has_lease(ci, sess->ClientGUID,
+ lctx);
+ if (m_opinfo) {
+ copy_lease(m_opinfo, opinfo);
+@@ -1240,7 +1241,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
+ {
+ struct oplock_info *op, *brk_op;
+ struct ksmbd_inode *ci;
+- struct ksmbd_conn *conn = work->sess->conn;
++ struct ksmbd_conn *conn = work->conn;
+
+ if (!test_share_config_flag(work->tcon->share_conf,
+ KSMBD_SHARE_FLAG_OPLOCKS))
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index 8bfe2a6c05f92..61d6d4b6b56ac 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -610,12 +610,9 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
+ if (!prev_user ||
+ strcmp(user->name, prev_user->name) ||
+ user->passkey_sz != prev_user->passkey_sz ||
+- memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) {
+- put_session(prev_sess);
++ memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
+ return;
+- }
+
+- put_session(prev_sess);
+ prev_sess->state = SMB2_SESSION_EXPIRED;
+ write_lock(&prev_sess->chann_lock);
+ list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
+@@ -1512,7 +1509,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+
+ if (smb3_encryption_negotiated(conn) &&
+ !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
+- rc = conn->ops->generate_encryptionkey(sess);
++ rc = conn->ops->generate_encryptionkey(conn, sess);
+ if (rc) {
+ ksmbd_debug(SMB,
+ "SMB3 encryption key generation failed\n");
+@@ -1604,7 +1601,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
+ sess->sign = true;
+
+ if (smb3_encryption_negotiated(conn)) {
+- retval = conn->ops->generate_encryptionkey(sess);
++ retval = conn->ops->generate_encryptionkey(conn, sess);
+ if (retval) {
+ ksmbd_debug(SMB,
+ "SMB3 encryption key generation failed\n");
+@@ -1692,7 +1689,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
+ goto out_err;
+ }
+
+- if (conn->dialect != sess->conn->dialect) {
++ if (conn->dialect != sess->dialect) {
+ rc = -EINVAL;
+ goto out_err;
+ }
+@@ -1702,7 +1699,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
+ goto out_err;
+ }
+
+- if (strncmp(conn->ClientGUID, sess->conn->ClientGUID,
++ if (strncmp(conn->ClientGUID, sess->ClientGUID,
+ SMB2_CLIENT_GUID_SIZE)) {
+ rc = -ENOENT;
+ goto out_err;
+@@ -1907,7 +1904,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
+ ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n",
+ name, treename);
+
+- status = ksmbd_tree_conn_connect(sess, name);
++ status = ksmbd_tree_conn_connect(conn, sess, name);
+ if (status.ret == KSMBD_TREE_CONN_STATUS_OK)
+ rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id);
+ else
+@@ -4895,7 +4892,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
+ struct smb2_query_info_rsp *rsp, void *rsp_org)
+ {
+ struct ksmbd_session *sess = work->sess;
+- struct ksmbd_conn *conn = sess->conn;
++ struct ksmbd_conn *conn = work->conn;
+ struct ksmbd_share_config *share = work->tcon->share_conf;
+ int fsinfoclass = 0;
+ struct kstatfs stfs;
+@@ -5831,7 +5828,7 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
+ }
+ next:
+ return smb2_rename(work, fp, user_ns, rename_info,
+- work->sess->conn->local_nls);
++ work->conn->local_nls);
+ }
+
+ static int set_file_disposition_info(struct ksmbd_file *fp,
+@@ -5965,7 +5962,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
+ return smb2_create_link(work, work->tcon->share_conf,
+ (struct smb2_file_link_info *)req->Buffer,
+ buf_len, fp->filp,
+- work->sess->conn->local_nls);
++ work->conn->local_nls);
+ }
+ case FILE_DISPOSITION_INFORMATION:
+ {
+diff --git a/fs/ksmbd/smb_common.h b/fs/ksmbd/smb_common.h
+index b9fe3fa149c2e..48cbaa0321400 100644
+--- a/fs/ksmbd/smb_common.h
++++ b/fs/ksmbd/smb_common.h
+@@ -454,7 +454,7 @@ struct smb_version_ops {
+ int (*check_sign_req)(struct ksmbd_work *work);
+ void (*set_sign_rsp)(struct ksmbd_work *work);
+ int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn);
+- int (*generate_encryptionkey)(struct ksmbd_session *sess);
++ int (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess);
+ bool (*is_transform_hdr)(void *buf);
+ int (*decrypt_req)(struct ksmbd_work *work);
+ int (*encrypt_resp)(struct ksmbd_work *work);
+diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c
+index 5d40a00fbce50..52cc6a9627ed7 100644
+--- a/fs/ksmbd/vfs.c
++++ b/fs/ksmbd/vfs.c
+@@ -483,12 +483,11 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
+ char *buf, size_t count, loff_t *pos, bool sync,
+ ssize_t *written)
+ {
+- struct ksmbd_session *sess = work->sess;
+ struct file *filp;
+ loff_t offset = *pos;
+ int err = 0;
+
+- if (sess->conn->connection_type) {
++ if (work->conn->connection_type) {
+ if (!(fp->daccess & FILE_WRITE_DATA_LE)) {
+ pr_err("no right to write(%pd)\n",
+ fp->filp->f_path.dentry);
+diff --git a/fs/ksmbd/vfs_cache.c b/fs/ksmbd/vfs_cache.c
+index 8b873d92d7854..0df8467af39af 100644
+--- a/fs/ksmbd/vfs_cache.c
++++ b/fs/ksmbd/vfs_cache.c
+@@ -570,7 +570,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
+ atomic_set(&fp->refcount, 1);
+
+ fp->filp = filp;
+- fp->conn = work->sess->conn;
++ fp->conn = work->conn;
+ fp->tcon = work->tcon;
+ fp->volatile_id = KSMBD_NO_FID;
+ fp->persistent_id = KSMBD_NO_FID;
+--
+2.39.2
+
--- /dev/null
+From fad4b1d8a9cb53e6994d1d833c87daf421122327 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 May 2023 08:45:08 +0900
+Subject: ksmbd: not allow guest user on multichannel
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 3353ab2df5f68dab7da8d5ebb427a2d265a1f2b2 ]
+
+This patch return STATUS_NOT_SUPPORTED if binding session is guest.
+
+Cc: stable@vger.kernel.org
+Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20480
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/smb2pdu.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index 61d6d4b6b56ac..51d495688f45e 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -1462,7 +1462,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+ * Reuse session if anonymous try to connect
+ * on reauthetication.
+ */
+- if (ksmbd_anonymous_user(user)) {
++ if (conn->binding == false && ksmbd_anonymous_user(user)) {
+ ksmbd_free_user(user);
+ return 0;
+ }
+@@ -1476,7 +1476,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+ sess->user = user;
+ }
+
+- if (user_guest(sess->user)) {
++ if (conn->binding == false && user_guest(sess->user)) {
+ rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE;
+ } else {
+ struct authenticate_message *authblob;
+@@ -1720,6 +1720,11 @@ int smb2_sess_setup(struct ksmbd_work *work)
+ goto out_err;
+ }
+
++ if (user_guest(sess->user)) {
++ rc = -EOPNOTSUPP;
++ goto out_err;
++ }
++
+ conn->binding = true;
+ } else if ((conn->dialect < SMB30_PROT_ID ||
+ server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
+@@ -1831,6 +1836,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
+ rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED;
+ else if (rc == -ENOMEM)
+ rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
++ else if (rc == -EOPNOTSUPP)
++ rsp->hdr.Status = STATUS_NOT_SUPPORTED;
+ else if (rc)
+ rsp->hdr.Status = STATUS_LOGON_FAILURE;
+
+--
+2.39.2
+
--- /dev/null
+From 1f1cf3e477e086b8bac077b54318929343b36823 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Jul 2022 10:15:10 +0900
+Subject: ksmbd: replace sessions list in connection with xarray
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit e4d3e6b524c0c928f7fc9e03e047885c4951ae60 ]
+
+Replace sessions list in connection with xarray.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 7b4323373d84 ("ksmbd: fix deadlock in ksmbd_find_crypto_ctx()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/connection.c | 3 ++-
+ fs/ksmbd/connection.h | 2 +-
+ fs/ksmbd/mgmt/user_session.c | 31 +++++++------------------------
+ fs/ksmbd/mgmt/user_session.h | 5 ++---
+ fs/ksmbd/smb2pdu.c | 13 +++++++++----
+ 5 files changed, 21 insertions(+), 33 deletions(-)
+
+diff --git a/fs/ksmbd/connection.c b/fs/ksmbd/connection.c
+index 21cda82f156de..b4c79359ef8b7 100644
+--- a/fs/ksmbd/connection.c
++++ b/fs/ksmbd/connection.c
+@@ -36,6 +36,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
+ list_del(&conn->conns_list);
+ write_unlock(&conn_list_lock);
+
++ xa_destroy(&conn->sessions);
+ kvfree(conn->request_buf);
+ kfree(conn->preauth_info);
+ kfree(conn);
+@@ -66,12 +67,12 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
+
+ init_waitqueue_head(&conn->req_running_q);
+ INIT_LIST_HEAD(&conn->conns_list);
+- INIT_LIST_HEAD(&conn->sessions);
+ INIT_LIST_HEAD(&conn->requests);
+ INIT_LIST_HEAD(&conn->async_requests);
+ spin_lock_init(&conn->request_lock);
+ spin_lock_init(&conn->credits_lock);
+ ida_init(&conn->async_ida);
++ xa_init(&conn->sessions);
+
+ spin_lock_init(&conn->llist_lock);
+ INIT_LIST_HEAD(&conn->lock_list);
+diff --git a/fs/ksmbd/connection.h b/fs/ksmbd/connection.h
+index f3367d7760d7e..7838cc46497d6 100644
+--- a/fs/ksmbd/connection.h
++++ b/fs/ksmbd/connection.h
+@@ -55,7 +55,7 @@ struct ksmbd_conn {
+ struct nls_table *local_nls;
+ struct list_head conns_list;
+ /* smb session 1 per user */
+- struct list_head sessions;
++ struct xarray sessions;
+ unsigned long last_active;
+ /* How many request are running currently */
+ atomic_t req_running;
+diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c
+index 0fa467f2c8973..8fe08df668582 100644
+--- a/fs/ksmbd/mgmt/user_session.c
++++ b/fs/ksmbd/mgmt/user_session.c
+@@ -154,8 +154,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
+ if (!atomic_dec_and_test(&sess->refcnt))
+ return;
+
+- list_del(&sess->sessions_entry);
+-
+ down_write(&sessions_table_lock);
+ hash_del(&sess->hlist);
+ up_write(&sessions_table_lock);
+@@ -183,42 +181,28 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
+ return NULL;
+ }
+
+-void ksmbd_session_register(struct ksmbd_conn *conn,
+- struct ksmbd_session *sess)
++int ksmbd_session_register(struct ksmbd_conn *conn,
++ struct ksmbd_session *sess)
+ {
+ sess->conn = conn;
+- list_add(&sess->sessions_entry, &conn->sessions);
++ return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
+ }
+
+ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
+ {
+ struct ksmbd_session *sess;
++ unsigned long id;
+
+- while (!list_empty(&conn->sessions)) {
+- sess = list_entry(conn->sessions.next,
+- struct ksmbd_session,
+- sessions_entry);
+-
++ xa_for_each(&conn->sessions, id, sess) {
++ xa_erase(&conn->sessions, sess->id);
+ ksmbd_session_destroy(sess);
+ }
+ }
+
+-static bool ksmbd_session_id_match(struct ksmbd_session *sess,
+- unsigned long long id)
+-{
+- return sess->id == id;
+-}
+-
+ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
+ unsigned long long id)
+ {
+- struct ksmbd_session *sess = NULL;
+-
+- list_for_each_entry(sess, &conn->sessions, sessions_entry) {
+- if (ksmbd_session_id_match(sess, id))
+- return sess;
+- }
+- return NULL;
++ return xa_load(&conn->sessions, id);
+ }
+
+ int get_session(struct ksmbd_session *sess)
+@@ -316,7 +300,6 @@ static struct ksmbd_session *__session_create(int protocol)
+ goto error;
+
+ set_session_flag(sess, protocol);
+- INIT_LIST_HEAD(&sess->sessions_entry);
+ xa_init(&sess->tree_conns);
+ INIT_LIST_HEAD(&sess->ksmbd_chann_list);
+ INIT_LIST_HEAD(&sess->rpc_handle_list);
+diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h
+index e241f16a38512..8b08189be3fc2 100644
+--- a/fs/ksmbd/mgmt/user_session.h
++++ b/fs/ksmbd/mgmt/user_session.h
+@@ -57,7 +57,6 @@ struct ksmbd_session {
+ __u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
+ __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
+
+- struct list_head sessions_entry;
+ struct ksmbd_file_table file_table;
+ atomic_t refcnt;
+ };
+@@ -84,8 +83,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
+ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
+ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
+ unsigned long long id);
+-void ksmbd_session_register(struct ksmbd_conn *conn,
+- struct ksmbd_session *sess);
++int ksmbd_session_register(struct ksmbd_conn *conn,
++ struct ksmbd_session *sess);
+ void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
+ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
+ unsigned long long id);
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index bb8126deeaf29..d41995f89befe 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -595,7 +595,8 @@ int smb2_check_user_session(struct ksmbd_work *work)
+ return -EINVAL;
+ }
+
+-static void destroy_previous_session(struct ksmbd_user *user, u64 id)
++static void destroy_previous_session(struct ksmbd_conn *conn,
++ struct ksmbd_user *user, u64 id)
+ {
+ struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
+ struct ksmbd_user *prev_user;
+@@ -614,6 +615,7 @@ static void destroy_previous_session(struct ksmbd_user *user, u64 id)
+ }
+
+ put_session(prev_sess);
++ xa_erase(&conn->sessions, prev_sess->id);
+ ksmbd_session_destroy(prev_sess);
+ }
+
+@@ -1452,7 +1454,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+ /* Check for previous session */
+ prev_id = le64_to_cpu(req->PreviousSessionId);
+ if (prev_id && prev_id != sess->id)
+- destroy_previous_session(user, prev_id);
++ destroy_previous_session(conn, user, prev_id);
+
+ if (sess->state == SMB2_SESSION_VALID) {
+ /*
+@@ -1575,7 +1577,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
+ /* Check previous session */
+ prev_sess_id = le64_to_cpu(req->PreviousSessionId);
+ if (prev_sess_id && prev_sess_id != sess->id)
+- destroy_previous_session(sess->user, prev_sess_id);
++ destroy_previous_session(conn, sess->user, prev_sess_id);
+
+ if (sess->state == SMB2_SESSION_VALID)
+ ksmbd_free_user(sess->user);
+@@ -1664,7 +1666,9 @@ int smb2_sess_setup(struct ksmbd_work *work)
+ goto out_err;
+ }
+ rsp->hdr.SessionId = cpu_to_le64(sess->id);
+- ksmbd_session_register(conn, sess);
++ rc = ksmbd_session_register(conn, sess);
++ if (rc)
++ goto out_err;
+ } else if (conn->dialect >= SMB30_PROT_ID &&
+ (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
+ req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) {
+@@ -1845,6 +1849,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
+ if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
+ try_delay = true;
+
++ xa_erase(&conn->sessions, sess->id);
+ ksmbd_session_destroy(sess);
+ work->sess = NULL;
+ if (try_delay)
+--
+2.39.2
+
--- /dev/null
+From 2e51f3e34f664076b1f2292e990f84b18a40bfc3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Dec 2021 10:26:43 +0900
+Subject: ksmbd: set RSS capable in FSCTL_QUERY_NETWORK_INTERFACE_INFO
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit a58b45a4dbfd0bf2ebb157789da4d8e6368afb1b ]
+
+Set RSS capable in FSCTL_QUERY_NETWORK_INTERFACE_INFO if netdev has
+multi tx queues. And add ksmbd_compare_user() to avoid racy condition
+issue in ksmbd_free_user(). because windows client is simultaneously used
+to send session setup requests for multichannel connection.
+
+Tested-by: Ziwei Xie <zw.xie@high-flyer.cn>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 7b4323373d84 ("ksmbd: fix deadlock in ksmbd_find_crypto_ctx()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/mgmt/user_config.c | 10 ++++++++++
+ fs/ksmbd/mgmt/user_config.h | 1 +
+ fs/ksmbd/smb2pdu.c | 15 ++++++++++-----
+ 3 files changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/fs/ksmbd/mgmt/user_config.c b/fs/ksmbd/mgmt/user_config.c
+index 1019d3677d553..279d00feff216 100644
+--- a/fs/ksmbd/mgmt/user_config.c
++++ b/fs/ksmbd/mgmt/user_config.c
+@@ -67,3 +67,13 @@ int ksmbd_anonymous_user(struct ksmbd_user *user)
+ return 1;
+ return 0;
+ }
++
++bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2)
++{
++ if (strcmp(u1->name, u2->name))
++ return false;
++ if (memcmp(u1->passkey, u2->passkey, u1->passkey_sz))
++ return false;
++
++ return true;
++}
+diff --git a/fs/ksmbd/mgmt/user_config.h b/fs/ksmbd/mgmt/user_config.h
+index aff80b0295790..6a44109617f14 100644
+--- a/fs/ksmbd/mgmt/user_config.h
++++ b/fs/ksmbd/mgmt/user_config.h
+@@ -64,4 +64,5 @@ struct ksmbd_user *ksmbd_login_user(const char *account);
+ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp);
+ void ksmbd_free_user(struct ksmbd_user *user);
+ int ksmbd_anonymous_user(struct ksmbd_user *user);
++bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2);
+ #endif /* __USER_CONFIG_MANAGEMENT_H__ */
+diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
+index 22d9fcb5f7ca4..c8c2b326ee042 100644
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -1463,10 +1463,16 @@ static int ntlm_authenticate(struct ksmbd_work *work)
+ ksmbd_free_user(user);
+ return 0;
+ }
+- ksmbd_free_user(sess->user);
++
++ if (!ksmbd_compare_user(sess->user, user)) {
++ ksmbd_free_user(user);
++ return -EPERM;
++ }
++ ksmbd_free_user(user);
++ } else {
++ sess->user = user;
+ }
+
+- sess->user = user;
+ if (user_guest(sess->user)) {
+ rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE;
+ } else {
+@@ -2071,9 +2077,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
+
+ ksmbd_debug(SMB, "request\n");
+
+- /* Got a valid session, set connection state */
+- WARN_ON(sess->conn != conn);
+-
+ /* setting CifsExiting here may race with start_tcp_sess */
+ ksmbd_conn_set_need_reconnect(work);
+ ksmbd_close_session_fds(work);
+@@ -7302,6 +7305,8 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn,
+ nii_rsp->IfIndex = cpu_to_le32(netdev->ifindex);
+
+ nii_rsp->Capability = 0;
++ if (netdev->real_num_tx_queues > 1)
++ nii_rsp->Capability |= cpu_to_le32(RSS_CAPABLE);
+ if (ksmbd_rdma_capable_netdev(netdev))
+ nii_rsp->Capability |= cpu_to_le32(RDMA_CAPABLE);
+
+--
+2.39.2
+
asoc-soc-pcm-move-debugfs-removal-out-of-spinlock.patch
asoc-dpcm-don-t-pick-up-be-without-substream.patch
asoc-soc-pcm.c-call-__soc_pcm_close-in-soc_pcm_close.patch
+drm-i915-dg2-support-4k-30-on-hdmi.patch
+drm-i915-dg2-add-additional-hdmi-pixel-clock-frequen.patch
+drm-i915-dg2-add-hdmi-pixel-clock-frequencies-267.30.patch
+drm-msm-remove-struct_mutex-usage.patch
+drm-msm-adreno-fix-runtime-pm-imbalance-at-gpu-load.patch
+drm-amd-display-refine-condition-of-cursor-visibilit.patch
+drm-amd-display-add-null-plane_state-check-for-curso.patch
+wifi-rtw88-rtw8821c-fix-rfe_option-field-width.patch
+ksmbd-set-rss-capable-in-fsctl_query_network_interfa.patch
+ksmbd-fix-multi-session-connection-failure.patch
+ksmbd-replace-sessions-list-in-connection-with-xarra.patch
+ksmbd-add-channel-rwlock.patch
+ksmbd-fix-kernel-oops-from-idr_remove.patch
+ksmbd-fix-racy-issue-while-destroying-session-on-mul.patch
+ksmbd-fix-deadlock-in-ksmbd_find_crypto_ctx.patch
+ksmbd-not-allow-guest-user-on-multichannel.patch
--- /dev/null
+From 8228ea44695e99e6db63c07c111d7d45c8bfc77a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Apr 2023 16:03:56 +0200
+Subject: wifi: rtw88: rtw8821c: Fix rfe_option field width
+
+From: Sascha Hauer <s.hauer@pengutronix.de>
+
+[ Upstream commit 14705f969d98187a1cc2682e0c9bd2e230b8098f ]
+
+On my RTW8821CU chipset rfe_option reads as 0x22. Looking at the
+vendor driver suggests that the field width of rfe_option is 5 bit,
+so rfe_option should be masked with 0x1f.
+
+Without this the rfe_option comparisons with 2 further down the
+driver evaluate as false when they should really evaluate as true.
+The effect is that 2G channels do not work.
+
+rfe_option is also used as an array index into rtw8821c_rfe_defs[].
+rtw8821c_rfe_defs[34] (0x22) was added as part of adding USB support,
+likely because rfe_option reads as 0x22. As this now becomes 0x2,
+rtw8821c_rfe_defs[34] is no longer used and can be removed.
+
+Note that this might not be the whole truth. In the vendor driver
+there are indeed places where the unmasked rfe_option value is used.
+However, the driver has several places where rfe_option is tested
+with the pattern if (rfe_option == 2 || rfe_option == 0x22) or
+if (rfe_option == 4 || rfe_option == 0x24), so that rfe_option BIT(5)
+has no influence on the code path taken. We therefore mask BIT(5)
+out from rfe_option entirely until this assumption is proved wrong
+by some chip variant we do not know yet.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+Tested-by: Alexandru gagniuc <mr.nuke.me@gmail.com>
+Tested-by: Larry Finger <Larry.Finger@lwfinger.net>
+Tested-by: ValdikSS <iam@valdikss.org.ru>
+Cc: stable@vger.kernel.org
+Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/20230417140358.2240429-3-s.hauer@pengutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/rtw8821c.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+index 897da3ed2f029..280602a34fe67 100644
+--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
++++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+@@ -40,7 +40,7 @@ static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
+
+ map = (struct rtw8821c_efuse *)log_map;
+
+- efuse->rfe_option = map->rfe_option;
++ efuse->rfe_option = map->rfe_option & 0x1f;
+ efuse->rf_board_option = map->rf_board_option;
+ efuse->crystal_cap = map->xtal_k;
+ efuse->pa_type_2g = map->pa_type;
+--
+2.39.2
+