diff options
author | graysky | 2023-01-14 09:14:43 -0500 |
---|---|---|
committer | graysky | 2023-01-14 09:14:43 -0500 |
commit | d117e52ce734b1eea0f7feb00d1a2c3d915d5e0a (patch) | |
tree | 6b4f17a063e286a5a93094248d312386f3d7c322 | |
parent | 3d7c25b337e883b18d2874cf11a44bff0fe481de (diff) | |
download | aur-d117e52ce734b1eea0f7feb00d1a2c3d915d5e0a.tar.gz |
Update to 6.1.6-1
-rw-r--r-- | .SRCINFO | 22 | ||||
-rw-r--r-- | 0001-ZEN-Add-sysctl-and-CONFIG-to-disallow-unprivileged-C.patch | 8 | ||||
-rw-r--r-- | 0002-docs-Fix-the-docs-build-with-Sphinx-6.0.patch | 48 | ||||
-rw-r--r-- | 0003-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch | 2478 | ||||
-rw-r--r-- | 0004-netfilter-nft_payload-incorrect-arithmetics-when-fet.patch | 41 | ||||
-rw-r--r-- | PKGBUILD | 18 | ||||
-rw-r--r-- | config | 3 |
7 files changed, 2597 insertions, 21 deletions
@@ -1,6 +1,6 @@ pkgbase = linux-ck - pkgver = 6.1.5 - pkgrel = 2 + pkgver = 6.1.6 + pkgrel = 1 url = https://wiki.archlinux.org/index.php/Linux-ck arch = x86_64 license = GPL2 @@ -12,22 +12,26 @@ pkgbase = linux-ck makedepends = tar makedepends = xz options = !strip - source = https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.1.5.tar.xz - source = https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.1.5.tar.sign + source = https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.1.6.tar.xz + source = https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.1.6.tar.sign source = config source = more-uarches-20221217.tar.gz::https://github.com/graysky2/kernel_compiler_patch/archive/20221217.tar.gz source = ck-hrtimer-fdbdf7e0ec56cd59e11d024c473e766429271a5c.tar.gz::https://github.com/graysky2/linux-patches/archive/fdbdf7e0ec56cd59e11d024c473e766429271a5c.tar.gz source = 0001-ZEN-Add-sysctl-and-CONFIG-to-disallow-unprivileged-C.patch - source = 0002-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch + source = 0002-docs-Fix-the-docs-build-with-Sphinx-6.0.patch + source = 0003-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch + source = 0004-netfilter-nft_payload-incorrect-arithmetics-when-fet.patch validpgpkeys = ABAF11C65A2970B130ABE3C479BE3E4300411886 validpgpkeys = 647F28654894E3BD457199BE38DBBDC86092693E - sha256sums = bc7f6d9a8a8bbe9a723e82346bba94b58d926f78bfba106b21e041e0290076fc + sha256sums = 3e4d8e561da5703a205ae8d7b2bed6c5c64fc4299eebcbfd20481e63b57d5ee3 sha256sums = SKIP - sha256sums = 0571ea17a2e38458096b679418197bbea8c414388f628d122517f3a1f3a31b3a + sha256sums = 1efa33aea067fa920880ef7fef3ec82f8d4cde21213eda34ac6534ca6879fca0 sha256sums = f1d586e111932890ad5e0df15d092fb9b3f87bae4ea17812aae9b0ec98fe2db0 sha256sums = 6d3b9cb4639c1c5eb4e2697aed0dbffa5b4a37d63a0861dec8315dd052723e0e - sha256sums = 00c7b866ba5393639d5ca2349883909ad6b1bedf6091e857c83f208e0838479c - sha256sums = 601a923873d2d598d5a615b09c2863aa8402ced6da24215d2b25eac3c4987ed3 + sha256sums = e804772a555fcd60140e0ea35f8269c57d7c32d3440f0ff06c044b21a8f4681e + sha256sums = a46f8d26cb20397b06812af7d56800a0994fcd263262e3ca5f22dc2247c2b623 + sha256sums = 59c4479ecd93ecc3c6ca452f24e4ec8bc92fec8a99109222e6ac457fc1ea5d12 + sha256sums = 05feb34e7ab03085dd7d4ae252bea419a7d13048b081451e1e23b31dcc2b58db pkgname = linux-ck pkgdesc = The Linux kernel and modules with ck's hrtimer patches diff --git a/0001-ZEN-Add-sysctl-and-CONFIG-to-disallow-unprivileged-C.patch b/0001-ZEN-Add-sysctl-and-CONFIG-to-disallow-unprivileged-C.patch index 94b3e44a4640..dc7ee9ff6b79 100644 --- a/0001-ZEN-Add-sysctl-and-CONFIG-to-disallow-unprivileged-C.patch +++ b/0001-ZEN-Add-sysctl-and-CONFIG-to-disallow-unprivileged-C.patch @@ -1,7 +1,7 @@ -From d93b3bdc50f2d4a69e1abc900a588d6cf3b4b75b Mon Sep 17 00:00:00 2001 +From 3cc300f383b8041c97534eca79c035b55c804a30 Mon Sep 17 00:00:00 2001 From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com> Date: Mon, 16 Sep 2019 04:53:20 +0200 -Subject: [PATCH 1/4] ZEN: Add sysctl and CONFIG to disallow unprivileged +Subject: [PATCH 1/5] ZEN: Add sysctl and CONFIG to disallow unprivileged CLONE_NEWUSER Our default behavior continues to match the vanilla kernel. @@ -36,10 +36,10 @@ index 45f09bec02c4..87b20e2ee274 100644 { return &init_user_ns; diff --git a/init/Kconfig b/init/Kconfig -index 94125d3b6893..9f7139b536f6 100644 +index 0c214af99085..d9ae969eae32 100644 --- a/init/Kconfig +++ b/init/Kconfig -@@ -1247,6 +1247,22 @@ config USER_NS +@@ -1251,6 +1251,22 @@ config USER_NS If unsure, say N. diff --git a/0002-docs-Fix-the-docs-build-with-Sphinx-6.0.patch b/0002-docs-Fix-the-docs-build-with-Sphinx-6.0.patch new file mode 100644 index 000000000000..2b4c19a5dbb6 --- /dev/null +++ b/0002-docs-Fix-the-docs-build-with-Sphinx-6.0.patch @@ -0,0 +1,48 @@ +From a3b216b0a5c2628624de605599aa6c16675578de Mon Sep 17 00:00:00 2001 +From: Jonathan Corbet <corbet@lwn.net> +Date: Wed, 4 Jan 2023 13:45:35 -0700 +Subject: [PATCH 2/5] docs: Fix the docs build with Sphinx 6.0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Sphinx 6.0 removed the execfile_() function, which we use as part of the +configuration process. They *did* warn us... Just open-code the +functionality as is done in Sphinx itself. + +Tested (using SPHINX_CONF, since this code is only executed with an +alternative config file) on various Sphinx versions from 2.5 through 6.0. + +Reported-by: Martin Liška <mliska@suse.cz> +Signed-off-by: Jonathan Corbet <corbet@lwn.net> +--- + Documentation/sphinx/load_config.py | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Documentation/sphinx/load_config.py b/Documentation/sphinx/load_config.py +index eeb394b39e2c..8b416bfd75ac 100644 +--- a/Documentation/sphinx/load_config.py ++++ b/Documentation/sphinx/load_config.py +@@ -3,7 +3,7 @@ + + import os + import sys +-from sphinx.util.pycompat import execfile_ ++from sphinx.util.osutil import fs_encoding + + # ------------------------------------------------------------------------------ + def loadConfig(namespace): +@@ -48,7 +48,9 @@ def loadConfig(namespace): + sys.stdout.write("load additional sphinx-config: %s\n" % config_file) + config = namespace.copy() + config['__file__'] = config_file +- execfile_(config_file, config) ++ with open(config_file, 'rb') as f: ++ code = compile(f.read(), fs_encoding, 'exec') ++ exec(code, config) + del config['__file__'] + namespace.update(config) + else: +-- +2.39.0 + diff --git a/0003-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch b/0003-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch new file mode 100644 index 000000000000..b8538d4609d7 --- /dev/null +++ b/0003-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch @@ -0,0 +1,2478 @@ +From 2dac8857deaeb3d9e22ae48f9c6e85ced2fd8d96 Mon Sep 17 00:00:00 2001 +From: Wayne Lin <Wayne.Lin@amd.com> +Date: Thu, 12 Jan 2023 16:50:44 +0800 +Subject: [PATCH 3/5] Revert "drm/display/dp_mst: Move all payload info into + the atomic state" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 4d07b0bc403403438d9cf88450506240c5faf92f. + +[Why] +Changes cause regression on amdgpu mst. +E.g. +In fill_dc_mst_payload_table_from_drm(), amdgpu expects to add/remove payload +one by one and call fill_dc_mst_payload_table_from_drm() to update the HW +maintained payload table. But previous change tries to go through all the +payloads in mst_state and update amdpug hw maintained table in once everytime +driver only tries to add/remove a specific payload stream only. The newly +design idea conflicts with the implementation in amdgpu nowadays. + +[How] +Revert this patch first. After addressing all regression problems caused by +this previous patch, will add it back and adjust it. + +Signed-off-by: Wayne Lin <Wayne.Lin@amd.com> +Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2171 +Cc: stable@vger.kernel.org # 6.1 +Cc: Lyude Paul <lyude@redhat.com> +Cc: Harry Wentland <harry.wentland@amd.com> +Cc: Mario Limonciello <mario.limonciello@amd.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Ben Skeggs <bskeggs@redhat.com> +Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> +Cc: Fangzhi Zuo <Jerry.Zuo@amd.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 53 +- + .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 104 ++- + .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 87 ++- + .../amd/display/include/link_service_types.h | 3 - + drivers/gpu/drm/display/drm_dp_mst_topology.c | 724 ++++++++++++------ + drivers/gpu/drm/i915/display/intel_dp_mst.c | 64 +- + drivers/gpu/drm/i915/display/intel_hdcp.c | 24 +- + drivers/gpu/drm/nouveau/dispnv50/disp.c | 169 ++-- + include/drm/display/drm_dp_mst_helper.h | 178 +++-- + 9 files changed, 876 insertions(+), 530 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index dacad8b85963..40defd664b49 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -6460,7 +6460,6 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, + const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct drm_dp_mst_topology_mgr *mst_mgr; + struct drm_dp_mst_port *mst_port; +- struct drm_dp_mst_topology_state *mst_state; + enum dc_color_depth color_depth; + int clock, bpp = 0; + bool is_y420 = false; +@@ -6474,13 +6473,6 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, + if (!crtc_state->connectors_changed && !crtc_state->mode_changed) + return 0; + +- mst_state = drm_atomic_get_mst_topology_state(state, mst_mgr); +- if (IS_ERR(mst_state)) +- return PTR_ERR(mst_state); +- +- if (!mst_state->pbn_div) +- mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_port->dc_link); +- + if (!state->duplicated) { + int max_bpc = conn_state->max_requested_bpc; + is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) && +@@ -6492,10 +6484,11 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, + clock = adjusted_mode->clock; + dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false); + } +- +- dm_new_connector_state->vcpi_slots = +- drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port, +- dm_new_connector_state->pbn); ++ dm_new_connector_state->vcpi_slots = drm_dp_atomic_find_time_slots(state, ++ mst_mgr, ++ mst_port, ++ dm_new_connector_state->pbn, ++ dm_mst_get_pbn_divider(aconnector->dc_link)); + if (dm_new_connector_state->vcpi_slots < 0) { + DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); + return dm_new_connector_state->vcpi_slots; +@@ -6566,14 +6559,17 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, + dm_conn_state->vcpi_slots = slot_num; + + ret = drm_dp_mst_atomic_enable_dsc(state, aconnector->port, +- dm_conn_state->pbn, false); ++ dm_conn_state->pbn, 0, false); + if (ret < 0) + return ret; + + continue; + } + +- vcpi = drm_dp_mst_atomic_enable_dsc(state, aconnector->port, pbn, true); ++ vcpi = drm_dp_mst_atomic_enable_dsc(state, ++ aconnector->port, ++ pbn, pbn_div, ++ true); + if (vcpi < 0) + return vcpi; + +@@ -9407,6 +9403,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; + #if defined(CONFIG_DRM_AMD_DC_DCN) + struct dsc_mst_fairness_vars vars[MAX_PIPES]; ++ struct drm_dp_mst_topology_state *mst_state; ++ struct drm_dp_mst_topology_mgr *mgr; + #endif + + trace_amdgpu_dm_atomic_check_begin(state); +@@ -9654,6 +9652,33 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + lock_and_validation_needed = true; + } + ++#if defined(CONFIG_DRM_AMD_DC_DCN) ++ /* set the slot info for each mst_state based on the link encoding format */ ++ for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { ++ struct amdgpu_dm_connector *aconnector; ++ struct drm_connector *connector; ++ struct drm_connector_list_iter iter; ++ u8 link_coding_cap; ++ ++ if (!mgr->mst_state ) ++ continue; ++ ++ drm_connector_list_iter_begin(dev, &iter); ++ drm_for_each_connector_iter(connector, &iter) { ++ int id = connector->index; ++ ++ if (id == mst_state->mgr->conn_base_id) { ++ aconnector = to_amdgpu_dm_connector(connector); ++ link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); ++ drm_dp_mst_update_slots(mst_state, link_coding_cap); ++ ++ break; ++ } ++ } ++ drm_connector_list_iter_end(&iter); ++ ++ } ++#endif + /** + * Streams and planes are reset when there are changes that affect + * bandwidth. Anything that affects bandwidth needs to go through +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +index f72c013d3a5b..c8f9d10fde17 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +@@ -27,7 +27,6 @@ + #include <linux/acpi.h> + #include <linux/i2c.h> + +-#include <drm/drm_atomic.h> + #include <drm/drm_probe_helper.h> + #include <drm/amdgpu_drm.h> + #include <drm/drm_edid.h> +@@ -120,27 +119,40 @@ enum dc_edid_status dm_helpers_parse_edid_caps( + } + + static void +-fill_dc_mst_payload_table_from_drm(struct drm_dp_mst_topology_state *mst_state, +- struct amdgpu_dm_connector *aconnector, +- struct dc_dp_mst_stream_allocation_table *table) ++fill_dc_mst_payload_table_from_drm(struct amdgpu_dm_connector *aconnector, ++ struct dc_dp_mst_stream_allocation_table *proposed_table) + { +- struct dc_dp_mst_stream_allocation_table new_table = { 0 }; +- struct dc_dp_mst_stream_allocation *sa; +- struct drm_dp_mst_atomic_payload *payload; +- +- /* Fill payload info*/ +- list_for_each_entry(payload, &mst_state->payloads, next) { +- if (payload->delete) +- continue; +- +- sa = &new_table.stream_allocations[new_table.stream_count]; +- sa->slot_count = payload->time_slots; +- sa->vcp_id = payload->vcpi; +- new_table.stream_count++; ++ int i; ++ struct drm_dp_mst_topology_mgr *mst_mgr = ++ &aconnector->mst_port->mst_mgr; ++ ++ mutex_lock(&mst_mgr->payload_lock); ++ ++ proposed_table->stream_count = 0; ++ ++ /* number of active streams */ ++ for (i = 0; i < mst_mgr->max_payloads; i++) { ++ if (mst_mgr->payloads[i].num_slots == 0) ++ break; /* end of vcp_id table */ ++ ++ ASSERT(mst_mgr->payloads[i].payload_state != ++ DP_PAYLOAD_DELETE_LOCAL); ++ ++ if (mst_mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL || ++ mst_mgr->payloads[i].payload_state == ++ DP_PAYLOAD_REMOTE) { ++ ++ struct dc_dp_mst_stream_allocation *sa = ++ &proposed_table->stream_allocations[ ++ proposed_table->stream_count]; ++ ++ sa->slot_count = mst_mgr->payloads[i].num_slots; ++ sa->vcp_id = mst_mgr->proposed_vcpis[i]->vcpi; ++ proposed_table->stream_count++; ++ } + } + +- /* Overwrite the old table */ +- *table = new_table; ++ mutex_unlock(&mst_mgr->payload_lock); + } + + void dm_helpers_dp_update_branch_info( +@@ -158,9 +170,11 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( + bool enable) + { + struct amdgpu_dm_connector *aconnector; +- struct drm_dp_mst_topology_state *mst_state; +- struct drm_dp_mst_atomic_payload *payload; ++ struct dm_connector_state *dm_conn_state; + struct drm_dp_mst_topology_mgr *mst_mgr; ++ struct drm_dp_mst_port *mst_port; ++ bool ret; ++ u8 link_coding_cap = DP_8b_10b_ENCODING; + + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + /* Accessing the connector state is required for vcpi_slots allocation +@@ -171,21 +185,40 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( + if (!aconnector || !aconnector->mst_port) + return false; + ++ dm_conn_state = to_dm_connector_state(aconnector->base.state); ++ + mst_mgr = &aconnector->mst_port->mst_mgr; +- mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); ++ ++ if (!mst_mgr->mst_state) ++ return false; ++ ++ mst_port = aconnector->port; ++ ++#if defined(CONFIG_DRM_AMD_DC_DCN) ++ link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); ++#endif ++ ++ if (enable) { ++ ++ ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, ++ dm_conn_state->pbn, ++ dm_conn_state->vcpi_slots); ++ if (!ret) ++ return false; ++ ++ } else { ++ drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port); ++ } + + /* It's OK for this to fail */ +- payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port); +- if (enable) +- drm_dp_add_payload_part1(mst_mgr, mst_state, payload); +- else +- drm_dp_remove_payload(mst_mgr, mst_state, payload); ++ drm_dp_update_payload_part1(mst_mgr, (link_coding_cap == DP_CAP_ANSI_128B132B) ? 0:1); + + /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or + * AUX message. The sequence is slot 1-63 allocated sequence for each + * stream. AMD ASIC stream slot allocation should follow the same + * sequence. copy DRM MST allocation to dc */ +- fill_dc_mst_payload_table_from_drm(mst_state, aconnector, proposed_table); ++ ++ fill_dc_mst_payload_table_from_drm(aconnector, proposed_table); + + return true; + } +@@ -242,9 +275,8 @@ bool dm_helpers_dp_mst_send_payload_allocation( + bool enable) + { + struct amdgpu_dm_connector *aconnector; +- struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_topology_mgr *mst_mgr; +- struct drm_dp_mst_atomic_payload *payload; ++ struct drm_dp_mst_port *mst_port; + enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD; + enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD; + +@@ -253,16 +285,19 @@ bool dm_helpers_dp_mst_send_payload_allocation( + if (!aconnector || !aconnector->mst_port) + return false; + ++ mst_port = aconnector->port; ++ + mst_mgr = &aconnector->mst_port->mst_mgr; +- mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); + +- payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port); ++ if (!mst_mgr->mst_state) ++ return false; ++ + if (!enable) { + set_flag = MST_CLEAR_ALLOCATED_PAYLOAD; + clr_flag = MST_ALLOCATE_NEW_PAYLOAD; + } + +- if (enable && drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload)) { ++ if (drm_dp_update_payload_part2(mst_mgr)) { + amdgpu_dm_set_mst_status(&aconnector->mst_status, + set_flag, false); + } else { +@@ -272,6 +307,9 @@ bool dm_helpers_dp_mst_send_payload_allocation( + clr_flag, false); + } + ++ if (!enable) ++ drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port); ++ + return true; + } + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index 6483ba266893..d57f1528a295 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -598,8 +598,15 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, + + dc_link_dp_get_max_link_enc_cap(aconnector->dc_link, &max_link_enc_cap); + aconnector->mst_mgr.cbs = &dm_mst_cbs; +- drm_dp_mst_topology_mgr_init(&aconnector->mst_mgr, adev_to_drm(dm->adev), +- &aconnector->dm_dp_aux.aux, 16, 4, aconnector->connector_id); ++ drm_dp_mst_topology_mgr_init( ++ &aconnector->mst_mgr, ++ adev_to_drm(dm->adev), ++ &aconnector->dm_dp_aux.aux, ++ 16, ++ 4, ++ max_link_enc_cap.lane_count, ++ drm_dp_bw_code_to_link_rate(max_link_enc_cap.link_rate), ++ aconnector->connector_id); + + drm_connector_attach_dp_subconnector_property(&aconnector->base); + } +@@ -703,13 +710,12 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn) + return dsc_config.bits_per_pixel; + } + +-static int increase_dsc_bpp(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_state *mst_state, +- struct dc_link *dc_link, +- struct dsc_mst_fairness_params *params, +- struct dsc_mst_fairness_vars *vars, +- int count, +- int k) ++static bool increase_dsc_bpp(struct drm_atomic_state *state, ++ struct dc_link *dc_link, ++ struct dsc_mst_fairness_params *params, ++ struct dsc_mst_fairness_vars *vars, ++ int count, ++ int k) + { + int i; + bool bpp_increased[MAX_PIPES]; +@@ -717,10 +723,13 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, + int min_initial_slack; + int next_index; + int remaining_to_increase = 0; ++ int pbn_per_timeslot; + int link_timeslots_used; + int fair_pbn_alloc; + int ret = 0; + ++ pbn_per_timeslot = dm_mst_get_pbn_divider(dc_link); ++ + for (i = 0; i < count; i++) { + if (vars[i + k].dsc_enabled) { + initial_slack[i] = +@@ -751,17 +760,18 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, + link_timeslots_used = 0; + + for (i = 0; i < count; i++) +- link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, mst_state->pbn_div); ++ link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, pbn_per_timeslot); + +- fair_pbn_alloc = +- (63 - link_timeslots_used) / remaining_to_increase * mst_state->pbn_div; ++ fair_pbn_alloc = (63 - link_timeslots_used) / remaining_to_increase * pbn_per_timeslot; + + if (initial_slack[next_index] > fair_pbn_alloc) { + vars[next_index].pbn += fair_pbn_alloc; ++ + ret = drm_dp_atomic_find_time_slots(state, + params[next_index].port->mgr, + params[next_index].port, +- vars[next_index].pbn); ++ vars[next_index].pbn, ++ pbn_per_timeslot); + if (ret < 0) + return ret; + +@@ -773,7 +783,8 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, + ret = drm_dp_atomic_find_time_slots(state, + params[next_index].port->mgr, + params[next_index].port, +- vars[next_index].pbn); ++ vars[next_index].pbn, ++ pbn_per_timeslot); + if (ret < 0) + return ret; + } +@@ -782,7 +793,8 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, + ret = drm_dp_atomic_find_time_slots(state, + params[next_index].port->mgr, + params[next_index].port, +- vars[next_index].pbn); ++ vars[next_index].pbn, ++ pbn_per_timeslot); + if (ret < 0) + return ret; + +@@ -794,7 +806,8 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, + ret = drm_dp_atomic_find_time_slots(state, + params[next_index].port->mgr, + params[next_index].port, +- vars[next_index].pbn); ++ vars[next_index].pbn, ++ pbn_per_timeslot); + if (ret < 0) + return ret; + } +@@ -850,10 +863,12 @@ static int try_disable_dsc(struct drm_atomic_state *state, + break; + + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps); ++ + ret = drm_dp_atomic_find_time_slots(state, + params[next_index].port->mgr, + params[next_index].port, +- vars[next_index].pbn); ++ vars[next_index].pbn, ++ dm_mst_get_pbn_divider(dc_link)); + if (ret < 0) + return ret; + +@@ -863,10 +878,12 @@ static int try_disable_dsc(struct drm_atomic_state *state, + vars[next_index].bpp_x16 = 0; + } else { + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps); ++ + ret = drm_dp_atomic_find_time_slots(state, + params[next_index].port->mgr, + params[next_index].port, +- vars[next_index].pbn); ++ vars[next_index].pbn, ++ dm_mst_get_pbn_divider(dc_link)); + if (ret < 0) + return ret; + } +@@ -877,31 +894,21 @@ static int try_disable_dsc(struct drm_atomic_state *state, + return 0; + } + +-static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, +- struct dc_state *dc_state, +- struct dc_link *dc_link, +- struct dsc_mst_fairness_vars *vars, +- struct drm_dp_mst_topology_mgr *mgr, +- int *link_vars_start_index) ++static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, ++ struct dc_state *dc_state, ++ struct dc_link *dc_link, ++ struct dsc_mst_fairness_vars *vars, ++ int *link_vars_start_index) + { ++ int i, k, ret; + struct dc_stream_state *stream; + struct dsc_mst_fairness_params params[MAX_PIPES]; + struct amdgpu_dm_connector *aconnector; +- struct drm_dp_mst_topology_state *mst_state = drm_atomic_get_mst_topology_state(state, mgr); + int count = 0; +- int i, k, ret; + bool debugfs_overwrite = false; + + memset(params, 0, sizeof(params)); + +- if (IS_ERR(mst_state)) +- return PTR_ERR(mst_state); +- +- mst_state->pbn_div = dm_mst_get_pbn_divider(dc_link); +-#if defined(CONFIG_DRM_AMD_DC_DCN) +- drm_dp_mst_update_slots(mst_state, dc_link_dp_mst_decide_link_encoding_format(dc_link)); +-#endif +- + /* Set up params */ + for (i = 0; i < dc_state->stream_count; i++) { + struct dc_dsc_policy dsc_policy = {0}; +@@ -961,7 +968,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, + vars[i + k].dsc_enabled = false; + vars[i + k].bpp_x16 = 0; + ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port, +- vars[i + k].pbn); ++ vars[i + k].pbn, dm_mst_get_pbn_divider(dc_link)); + if (ret < 0) + return ret; + } +@@ -980,7 +987,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, + vars[i + k].dsc_enabled = true; + vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16; + ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, +- params[i].port, vars[i + k].pbn); ++ params[i].port, vars[i + k].pbn, dm_mst_get_pbn_divider(dc_link)); + if (ret < 0) + return ret; + } else { +@@ -988,7 +995,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, + vars[i + k].dsc_enabled = false; + vars[i + k].bpp_x16 = 0; + ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, +- params[i].port, vars[i + k].pbn); ++ params[i].port, vars[i + k].pbn, dm_mst_get_pbn_divider(dc_link)); + if (ret < 0) + return ret; + } +@@ -998,7 +1005,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, + return ret; + + /* Optimize degree of compression */ +- ret = increase_dsc_bpp(state, mst_state, dc_link, params, vars, count, k); ++ ret = increase_dsc_bpp(state, dc_link, params, vars, count, k); + if (ret < 0) + return ret; + +@@ -1148,7 +1155,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, + continue; + + mst_mgr = aconnector->port->mgr; +- ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr, ++ ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, + &link_vars_start_index); + if (ret != 0) + return ret; +@@ -1206,7 +1213,7 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, + continue; + + mst_mgr = aconnector->port->mgr; +- ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr, ++ ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, + &link_vars_start_index); + if (ret != 0) + return ret; +diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h +index d1e91d31d151..0889c2a86733 100644 +--- a/drivers/gpu/drm/amd/display/include/link_service_types.h ++++ b/drivers/gpu/drm/amd/display/include/link_service_types.h +@@ -252,9 +252,6 @@ union dpcd_training_lane_set { + * _ONLY_ be filled out from DM and then passed to DC, do NOT use these for _any_ kind of atomic + * state calculations in DM, or you will break something. + */ +- +-struct drm_dp_mst_port; +- + /* DP MST stream allocation (payload bandwidth number) */ + struct dc_dp_mst_stream_allocation { + uint8_t vcp_id; +diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c +index 51a46689cda7..95ff57d20216 100644 +--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c ++++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c +@@ -68,7 +68,8 @@ static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr, + static void drm_dp_mst_topology_put_port(struct drm_dp_mst_port *port); + + static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, +- int id, u8 start_slot, u8 num_slots); ++ int id, ++ struct drm_dp_payload *payload); + + static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, +@@ -1234,6 +1235,57 @@ build_query_stream_enc_status(struct drm_dp_sideband_msg_tx *msg, u8 stream_id, + return 0; + } + ++static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, ++ struct drm_dp_vcpi *vcpi) ++{ ++ int ret, vcpi_ret; ++ ++ mutex_lock(&mgr->payload_lock); ++ ret = find_first_zero_bit(&mgr->payload_mask, mgr->max_payloads + 1); ++ if (ret > mgr->max_payloads) { ++ ret = -EINVAL; ++ drm_dbg_kms(mgr->dev, "out of payload ids %d\n", ret); ++ goto out_unlock; ++ } ++ ++ vcpi_ret = find_first_zero_bit(&mgr->vcpi_mask, mgr->max_payloads + 1); ++ if (vcpi_ret > mgr->max_payloads) { ++ ret = -EINVAL; ++ drm_dbg_kms(mgr->dev, "out of vcpi ids %d\n", ret); ++ goto out_unlock; ++ } ++ ++ set_bit(ret, &mgr->payload_mask); ++ set_bit(vcpi_ret, &mgr->vcpi_mask); ++ vcpi->vcpi = vcpi_ret + 1; ++ mgr->proposed_vcpis[ret - 1] = vcpi; ++out_unlock: ++ mutex_unlock(&mgr->payload_lock); ++ return ret; ++} ++ ++static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr, ++ int vcpi) ++{ ++ int i; ++ ++ if (vcpi == 0) ++ return; ++ ++ mutex_lock(&mgr->payload_lock); ++ drm_dbg_kms(mgr->dev, "putting payload %d\n", vcpi); ++ clear_bit(vcpi - 1, &mgr->vcpi_mask); ++ ++ for (i = 0; i < mgr->max_payloads; i++) { ++ if (mgr->proposed_vcpis[i] && ++ mgr->proposed_vcpis[i]->vcpi == vcpi) { ++ mgr->proposed_vcpis[i] = NULL; ++ clear_bit(i + 1, &mgr->payload_mask); ++ } ++ } ++ mutex_unlock(&mgr->payload_lock); ++} ++ + static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_tx *txmsg) + { +@@ -1686,7 +1738,7 @@ drm_dp_mst_dump_port_topology_history(struct drm_dp_mst_port *port) {} + #define save_port_topology_ref(port, type) + #endif + +-struct drm_dp_mst_atomic_payload * ++static struct drm_dp_mst_atomic_payload * + drm_atomic_get_mst_payload_state(struct drm_dp_mst_topology_state *state, + struct drm_dp_mst_port *port) + { +@@ -1698,7 +1750,6 @@ drm_atomic_get_mst_payload_state(struct drm_dp_mst_topology_state *state, + + return NULL; + } +-EXPORT_SYMBOL(drm_atomic_get_mst_payload_state); + + static void drm_dp_destroy_mst_branch_device(struct kref *kref) + { +@@ -3201,8 +3252,6 @@ int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + struct drm_dp_query_stream_enc_status_ack_reply *status) + { +- struct drm_dp_mst_topology_state *state; +- struct drm_dp_mst_atomic_payload *payload; + struct drm_dp_sideband_msg_tx *txmsg; + u8 nonce[7]; + int ret; +@@ -3219,10 +3268,6 @@ int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, + + get_random_bytes(nonce, sizeof(nonce)); + +- drm_modeset_lock(&mgr->base.lock, NULL); +- state = to_drm_dp_mst_topology_state(mgr->base.state); +- payload = drm_atomic_get_mst_payload_state(state, port); +- + /* + * "Source device targets the QUERY_STREAM_ENCRYPTION_STATUS message + * transaction at the MST Branch device directly connected to the +@@ -3230,7 +3275,7 @@ int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, + */ + txmsg->dst = mgr->mst_primary; + +- build_query_stream_enc_status(txmsg, payload->vcpi, nonce); ++ build_query_stream_enc_status(txmsg, port->vcpi.vcpi, nonce); + + drm_dp_queue_down_tx(mgr, txmsg); + +@@ -3247,7 +3292,6 @@ int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, + memcpy(status, &txmsg->reply.u.enc_status, sizeof(*status)); + + out: +- drm_modeset_unlock(&mgr->base.lock); + drm_dp_mst_topology_put_port(port); + out_get_port: + kfree(txmsg); +@@ -3256,162 +3300,238 @@ int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr, + EXPORT_SYMBOL(drm_dp_send_query_stream_enc_status); + + static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_atomic_payload *payload) ++ int id, ++ struct drm_dp_payload *payload) + { +- return drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, +- payload->time_slots); ++ int ret; ++ ++ ret = drm_dp_dpcd_write_payload(mgr, id, payload); ++ if (ret < 0) { ++ payload->payload_state = 0; ++ return ret; ++ } ++ payload->payload_state = DP_PAYLOAD_LOCAL; ++ return 0; + } + + static int drm_dp_create_payload_step2(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_atomic_payload *payload) ++ struct drm_dp_mst_port *port, ++ int id, ++ struct drm_dp_payload *payload) + { + int ret; +- struct drm_dp_mst_port *port = drm_dp_mst_topology_get_port_validated(mgr, payload->port); +- +- if (!port) +- return -EIO; + +- ret = drm_dp_payload_send_msg(mgr, port, payload->vcpi, payload->pbn); +- drm_dp_mst_topology_put_port(port); ++ ret = drm_dp_payload_send_msg(mgr, port, id, port->vcpi.pbn); ++ if (ret < 0) ++ return ret; ++ payload->payload_state = DP_PAYLOAD_REMOTE; + return ret; + } + + static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_topology_state *mst_state, +- struct drm_dp_mst_atomic_payload *payload) ++ struct drm_dp_mst_port *port, ++ int id, ++ struct drm_dp_payload *payload) + { + drm_dbg_kms(mgr->dev, "\n"); +- + /* it's okay for these to fail */ +- drm_dp_payload_send_msg(mgr, payload->port, payload->vcpi, 0); +- drm_dp_dpcd_write_payload(mgr, payload->vcpi, payload->vc_start_slot, 0); ++ if (port) { ++ drm_dp_payload_send_msg(mgr, port, id, 0); ++ } + ++ drm_dp_dpcd_write_payload(mgr, id, payload); ++ payload->payload_state = DP_PAYLOAD_DELETE_LOCAL; ++ return 0; ++} ++ ++static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr, ++ int id, ++ struct drm_dp_payload *payload) ++{ ++ payload->payload_state = 0; + return 0; + } + + /** +- * drm_dp_add_payload_part1() - Execute payload update part 1 +- * @mgr: Manager to use. +- * @mst_state: The MST atomic state +- * @payload: The payload to write ++ * drm_dp_update_payload_part1() - Execute payload update part 1 ++ * @mgr: manager to use. ++ * @start_slot: this is the cur slot ++ * ++ * NOTE: start_slot is a temporary workaround for non-atomic drivers, ++ * this will be removed when non-atomic mst helpers are moved out of the helper + * +- * Determines the starting time slot for the given payload, and programs the VCPI for this payload +- * into hardware. After calling this, the driver should generate ACT and payload packets. ++ * This iterates over all proposed virtual channels, and tries to ++ * allocate space in the link for them. For 0->slots transitions, ++ * this step just writes the VCPI to the MST device. For slots->0 ++ * transitions, this writes the updated VCPIs and removes the ++ * remote VC payloads. + * +- * Returns: 0 on success, error code on failure. In the event that this fails, +- * @payload.vc_start_slot will also be set to -1. ++ * after calling this the driver should generate ACT and payload ++ * packets. + */ +-int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_topology_state *mst_state, +- struct drm_dp_mst_atomic_payload *payload) ++int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr, int start_slot) + { ++ struct drm_dp_payload req_payload; + struct drm_dp_mst_port *port; +- int ret; ++ int i, j; ++ int cur_slots = start_slot; ++ bool skip; + +- port = drm_dp_mst_topology_get_port_validated(mgr, payload->port); +- if (!port) +- return 0; ++ mutex_lock(&mgr->payload_lock); ++ for (i = 0; i < mgr->max_payloads; i++) { ++ struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i]; ++ struct drm_dp_payload *payload = &mgr->payloads[i]; ++ bool put_port = false; + +- if (mgr->payload_count == 0) +- mgr->next_start_slot = mst_state->start_slot; ++ /* solve the current payloads - compare to the hw ones ++ - update the hw view */ ++ req_payload.start_slot = cur_slots; ++ if (vcpi) { ++ port = container_of(vcpi, struct drm_dp_mst_port, ++ vcpi); + +- payload->vc_start_slot = mgr->next_start_slot; ++ mutex_lock(&mgr->lock); ++ skip = !drm_dp_mst_port_downstream_of_branch(port, mgr->mst_primary); ++ mutex_unlock(&mgr->lock); + +- ret = drm_dp_create_payload_step1(mgr, payload); +- drm_dp_mst_topology_put_port(port); +- if (ret < 0) { +- drm_warn(mgr->dev, "Failed to create MST payload for port %p: %d\n", +- payload->port, ret); +- payload->vc_start_slot = -1; +- return ret; +- } ++ if (skip) { ++ drm_dbg_kms(mgr->dev, ++ "Virtual channel %d is not in current topology\n", ++ i); ++ continue; ++ } ++ /* Validated ports don't matter if we're releasing ++ * VCPI ++ */ ++ if (vcpi->num_slots) { ++ port = drm_dp_mst_topology_get_port_validated( ++ mgr, port); ++ if (!port) { ++ if (vcpi->num_slots == payload->num_slots) { ++ cur_slots += vcpi->num_slots; ++ payload->start_slot = req_payload.start_slot; ++ continue; ++ } else { ++ drm_dbg_kms(mgr->dev, ++ "Fail:set payload to invalid sink"); ++ mutex_unlock(&mgr->payload_lock); ++ return -EINVAL; ++ } ++ } ++ put_port = true; ++ } + +- mgr->payload_count++; +- mgr->next_start_slot += payload->time_slots; ++ req_payload.num_slots = vcpi->num_slots; ++ req_payload.vcpi = vcpi->vcpi; ++ } else { ++ port = NULL; ++ req_payload.num_slots = 0; ++ } + +- return 0; +-} +-EXPORT_SYMBOL(drm_dp_add_payload_part1); ++ payload->start_slot = req_payload.start_slot; ++ /* work out what is required to happen with this payload */ ++ if (payload->num_slots != req_payload.num_slots) { ++ ++ /* need to push an update for this payload */ ++ if (req_payload.num_slots) { ++ drm_dp_create_payload_step1(mgr, vcpi->vcpi, ++ &req_payload); ++ payload->num_slots = req_payload.num_slots; ++ payload->vcpi = req_payload.vcpi; ++ ++ } else if (payload->num_slots) { ++ payload->num_slots = 0; ++ drm_dp_destroy_payload_step1(mgr, port, ++ payload->vcpi, ++ payload); ++ req_payload.payload_state = ++ payload->payload_state; ++ payload->start_slot = 0; ++ } ++ payload->payload_state = req_payload.payload_state; ++ } ++ cur_slots += req_payload.num_slots; + +-/** +- * drm_dp_remove_payload() - Remove an MST payload +- * @mgr: Manager to use. +- * @mst_state: The MST atomic state +- * @payload: The payload to write +- * +- * Removes a payload from an MST topology if it was successfully assigned a start slot. Also updates +- * the starting time slots of all other payloads which would have been shifted towards the start of +- * the VC table as a result. After calling this, the driver should generate ACT and payload packets. +- */ +-void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_topology_state *mst_state, +- struct drm_dp_mst_atomic_payload *payload) +-{ +- struct drm_dp_mst_atomic_payload *pos; +- bool send_remove = false; ++ if (put_port) ++ drm_dp_mst_topology_put_port(port); ++ } + +- /* We failed to make the payload, so nothing to do */ +- if (payload->vc_start_slot == -1) +- return; ++ for (i = 0; i < mgr->max_payloads; /* do nothing */) { ++ if (mgr->payloads[i].payload_state != DP_PAYLOAD_DELETE_LOCAL) { ++ i++; ++ continue; ++ } + +- mutex_lock(&mgr->lock); +- send_remove = drm_dp_mst_port_downstream_of_branch(payload->port, mgr->mst_primary); +- mutex_unlock(&mgr->lock); ++ drm_dbg_kms(mgr->dev, "removing payload %d\n", i); ++ for (j = i; j < mgr->max_payloads - 1; j++) { ++ mgr->payloads[j] = mgr->payloads[j + 1]; ++ mgr->proposed_vcpis[j] = mgr->proposed_vcpis[j + 1]; + +- if (send_remove) +- drm_dp_destroy_payload_step1(mgr, mst_state, payload); +- else +- drm_dbg_kms(mgr->dev, "Payload for VCPI %d not in topology, not sending remove\n", +- payload->vcpi); ++ if (mgr->proposed_vcpis[j] && ++ mgr->proposed_vcpis[j]->num_slots) { ++ set_bit(j + 1, &mgr->payload_mask); ++ } else { ++ clear_bit(j + 1, &mgr->payload_mask); ++ } ++ } + +- list_for_each_entry(pos, &mst_state->payloads, next) { +- if (pos != payload && pos->vc_start_slot > payload->vc_start_slot) +- pos->vc_start_slot -= payload->time_slots; ++ memset(&mgr->payloads[mgr->max_payloads - 1], 0, ++ sizeof(struct drm_dp_payload)); ++ mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL; ++ clear_bit(mgr->max_payloads, &mgr->payload_mask); + } +- payload->vc_start_slot = -1; ++ mutex_unlock(&mgr->payload_lock); + +- mgr->payload_count--; +- mgr->next_start_slot -= payload->time_slots; ++ return 0; + } +-EXPORT_SYMBOL(drm_dp_remove_payload); ++EXPORT_SYMBOL(drm_dp_update_payload_part1); + + /** +- * drm_dp_add_payload_part2() - Execute payload update part 2 +- * @mgr: Manager to use. +- * @state: The global atomic state +- * @payload: The payload to update +- * +- * If @payload was successfully assigned a starting time slot by drm_dp_add_payload_part1(), this +- * function will send the sideband messages to finish allocating this payload. ++ * drm_dp_update_payload_part2() - Execute payload update part 2 ++ * @mgr: manager to use. + * +- * Returns: 0 on success, negative error code on failure. ++ * This iterates over all proposed virtual channels, and tries to ++ * allocate space in the link for them. For 0->slots transitions, ++ * this step writes the remote VC payload commands. For slots->0 ++ * this just resets some internal state. + */ +-int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_atomic_state *state, +- struct drm_dp_mst_atomic_payload *payload) ++int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr) + { ++ struct drm_dp_mst_port *port; ++ int i; + int ret = 0; ++ bool skip; + +- /* Skip failed payloads */ +- if (payload->vc_start_slot == -1) { +- drm_dbg_kms(state->dev, "Part 1 of payload creation for %s failed, skipping part 2\n", +- payload->port->connector->name); +- return -EIO; +- } ++ mutex_lock(&mgr->payload_lock); ++ for (i = 0; i < mgr->max_payloads; i++) { + +- ret = drm_dp_create_payload_step2(mgr, payload); +- if (ret < 0) { +- if (!payload->delete) +- drm_err(mgr->dev, "Step 2 of creating MST payload for %p failed: %d\n", +- payload->port, ret); +- else +- drm_dbg_kms(mgr->dev, "Step 2 of removing MST payload for %p failed: %d\n", +- payload->port, ret); +- } ++ if (!mgr->proposed_vcpis[i]) ++ continue; + +- return ret; ++ port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi); ++ ++ mutex_lock(&mgr->lock); ++ skip = !drm_dp_mst_port_downstream_of_branch(port, mgr->mst_primary); ++ mutex_unlock(&mgr->lock); ++ ++ if (skip) ++ continue; ++ ++ drm_dbg_kms(mgr->dev, "payload %d %d\n", i, mgr->payloads[i].payload_state); ++ if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) { ++ ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]); ++ } else if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) { ++ ret = drm_dp_destroy_payload_step2(mgr, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]); ++ } ++ if (ret) { ++ mutex_unlock(&mgr->payload_lock); ++ return ret; ++ } ++ } ++ mutex_unlock(&mgr->payload_lock); ++ return 0; + } +-EXPORT_SYMBOL(drm_dp_add_payload_part2); ++EXPORT_SYMBOL(drm_dp_update_payload_part2); + + static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, +@@ -3591,6 +3711,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms + int ret = 0; + struct drm_dp_mst_branch *mstb = NULL; + ++ mutex_lock(&mgr->payload_lock); + mutex_lock(&mgr->lock); + if (mst_state == mgr->mst_state) + goto out_unlock; +@@ -3598,6 +3719,10 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms + mgr->mst_state = mst_state; + /* set the device into MST mode */ + if (mst_state) { ++ struct drm_dp_payload reset_pay; ++ int lane_count; ++ int link_rate; ++ + WARN_ON(mgr->mst_primary); + + /* get dpcd info */ +@@ -3608,6 +3733,16 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms + goto out_unlock; + } + ++ lane_count = min_t(int, mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK, mgr->max_lane_count); ++ link_rate = min_t(int, drm_dp_bw_code_to_link_rate(mgr->dpcd[1]), mgr->max_link_rate); ++ mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr, ++ link_rate, ++ lane_count); ++ if (mgr->pbn_div == 0) { ++ ret = -EINVAL; ++ goto out_unlock; ++ } ++ + /* add initial branch device at LCT 1 */ + mstb = drm_dp_add_mst_branch_device(1, NULL); + if (mstb == NULL) { +@@ -3627,8 +3762,9 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms + if (ret < 0) + goto out_unlock; + +- /* Write reset payload */ +- drm_dp_dpcd_write_payload(mgr, 0, 0, 0x3f); ++ reset_pay.start_slot = 0; ++ reset_pay.num_slots = 0x3f; ++ drm_dp_dpcd_write_payload(mgr, 0, &reset_pay); + + queue_work(system_long_wq, &mgr->work); + +@@ -3640,11 +3776,19 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms + /* this can fail if the device is gone */ + drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0); + ret = 0; ++ memset(mgr->payloads, 0, ++ mgr->max_payloads * sizeof(mgr->payloads[0])); ++ memset(mgr->proposed_vcpis, 0, ++ mgr->max_payloads * sizeof(mgr->proposed_vcpis[0])); ++ mgr->payload_mask = 0; ++ set_bit(0, &mgr->payload_mask); ++ mgr->vcpi_mask = 0; + mgr->payload_id_table_cleared = false; + } + + out_unlock: + mutex_unlock(&mgr->lock); ++ mutex_unlock(&mgr->payload_lock); + if (mstb) + drm_dp_mst_topology_put_mstb(mstb); + return ret; +@@ -4163,18 +4307,62 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ + } + EXPORT_SYMBOL(drm_dp_mst_get_edid); + ++/** ++ * drm_dp_find_vcpi_slots() - Find time slots for this PBN value ++ * @mgr: manager to use ++ * @pbn: payload bandwidth to convert into slots. ++ * ++ * Calculate the number of time slots that will be required for the given PBN ++ * value. This function is deprecated, and should not be used in atomic ++ * drivers. ++ * ++ * RETURNS: ++ * The total slots required for this port, or error. ++ */ ++int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, ++ int pbn) ++{ ++ int num_slots; ++ ++ num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); ++ ++ /* max. time slots - one slot for MTP header */ ++ if (num_slots > 63) ++ return -ENOSPC; ++ return num_slots; ++} ++EXPORT_SYMBOL(drm_dp_find_vcpi_slots); ++ ++static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, ++ struct drm_dp_vcpi *vcpi, int pbn, int slots) ++{ ++ int ret; ++ ++ vcpi->pbn = pbn; ++ vcpi->aligned_pbn = slots * mgr->pbn_div; ++ vcpi->num_slots = slots; ++ ++ ret = drm_dp_mst_assign_payload_id(mgr, vcpi); ++ if (ret < 0) ++ return ret; ++ return 0; ++} ++ + /** + * drm_dp_atomic_find_time_slots() - Find and add time slots to the state + * @state: global atomic state + * @mgr: MST topology manager for the port + * @port: port to find time slots for + * @pbn: bandwidth required for the mode in PBN ++ * @pbn_div: divider for DSC mode that takes FEC into account + * +- * Allocates time slots to @port, replacing any previous time slot allocations it may +- * have had. Any atomic drivers which support MST must call this function in +- * their &drm_encoder_helper_funcs.atomic_check() callback unconditionally to +- * change the current time slot allocation for the new state, and ensure the MST +- * atomic state is added whenever the state of payloads in the topology changes. ++ * Allocates time slots to @port, replacing any previous timeslot allocations it ++ * may have had. Any atomic drivers which support MST must call this function ++ * in their &drm_encoder_helper_funcs.atomic_check() callback to change the ++ * current timeslot allocation for the new state, but only when ++ * &drm_crtc_state.mode_changed or &drm_crtc_state.connectors_changed is set ++ * to ensure compatibility with userspace applications that still use the ++ * legacy modesetting UAPI. + * + * Allocations set by this function are not checked against the bandwidth + * restraints of @mgr until the driver calls drm_dp_mst_atomic_check(). +@@ -4193,7 +4381,8 @@ EXPORT_SYMBOL(drm_dp_mst_get_edid); + */ + int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_port *port, int pbn) ++ struct drm_dp_mst_port *port, int pbn, ++ int pbn_div) + { + struct drm_dp_mst_topology_state *topology_state; + struct drm_dp_mst_atomic_payload *payload = NULL; +@@ -4226,7 +4415,10 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, + } + } + +- req_slots = DIV_ROUND_UP(pbn, topology_state->pbn_div); ++ if (pbn_div <= 0) ++ pbn_div = mgr->pbn_div; ++ ++ req_slots = DIV_ROUND_UP(pbn, pbn_div); + + drm_dbg_atomic(mgr->dev, "[CONNECTOR:%d:%s] [MST PORT:%p] TU %d -> %d\n", + port->connector->base.id, port->connector->name, +@@ -4235,7 +4427,7 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, + port->connector->base.id, port->connector->name, + port, prev_bw, pbn); + +- /* Add the new allocation to the state, note the VCPI isn't assigned until the end */ ++ /* Add the new allocation to the state */ + if (!payload) { + payload = kzalloc(sizeof(*payload), GFP_KERNEL); + if (!payload) +@@ -4243,7 +4435,6 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, + + drm_dp_mst_get_port_malloc(port); + payload->port = port; +- payload->vc_start_slot = -1; + list_add(&payload->next, &topology_state->payloads); + } + payload->time_slots = req_slots; +@@ -4260,12 +4451,10 @@ EXPORT_SYMBOL(drm_dp_atomic_find_time_slots); + * @port: The port to release the time slots from + * + * Releases any time slots that have been allocated to a port in the atomic +- * state. Any atomic drivers which support MST must call this function +- * unconditionally in their &drm_connector_helper_funcs.atomic_check() callback. +- * This helper will check whether time slots would be released by the new state and +- * respond accordingly, along with ensuring the MST state is always added to the +- * atomic state whenever a new state would modify the state of payloads on the +- * topology. ++ * state. Any atomic drivers which support MST must call this function in ++ * their &drm_connector_helper_funcs.atomic_check() callback when the ++ * connector will no longer have VCPI allocated (e.g. because its CRTC was ++ * removed) when it had VCPI allocated in the previous atomic state. + * + * It is OK to call this even if @port has been removed from the system. + * Additionally, it is OK to call this function multiple times on the same +@@ -4330,7 +4519,6 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state, + drm_dp_mst_put_port_malloc(port); + payload->pbn = 0; + payload->delete = true; +- topology_state->payload_mask &= ~BIT(payload->vcpi - 1); + } + + return 0; +@@ -4381,8 +4569,7 @@ int drm_dp_mst_atomic_setup_commit(struct drm_atomic_state *state) + EXPORT_SYMBOL(drm_dp_mst_atomic_setup_commit); + + /** +- * drm_dp_mst_atomic_wait_for_dependencies() - Wait for all pending commits on MST topologies, +- * prepare new MST state for commit ++ * drm_dp_mst_atomic_wait_for_dependencies() - Wait for all pending commits on MST topologies + * @state: global atomic state + * + * Goes through any MST topologies in this atomic state, and waits for any pending commits which +@@ -4400,30 +4587,17 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_setup_commit); + */ + void drm_dp_mst_atomic_wait_for_dependencies(struct drm_atomic_state *state) + { +- struct drm_dp_mst_topology_state *old_mst_state, *new_mst_state; ++ struct drm_dp_mst_topology_state *old_mst_state; + struct drm_dp_mst_topology_mgr *mgr; +- struct drm_dp_mst_atomic_payload *old_payload, *new_payload; + int i, j, ret; + +- for_each_oldnew_mst_mgr_in_state(state, mgr, old_mst_state, new_mst_state, i) { ++ for_each_old_mst_mgr_in_state(state, mgr, old_mst_state, i) { + for (j = 0; j < old_mst_state->num_commit_deps; j++) { + ret = drm_crtc_commit_wait(old_mst_state->commit_deps[j]); + if (ret < 0) + drm_err(state->dev, "Failed to wait for %s: %d\n", + old_mst_state->commit_deps[j]->crtc->name, ret); + } +- +- /* Now that previous state is committed, it's safe to copy over the start slot +- * assignments +- */ +- list_for_each_entry(old_payload, &old_mst_state->payloads, next) { +- if (old_payload->delete) +- continue; +- +- new_payload = drm_atomic_get_mst_payload_state(new_mst_state, +- old_payload->port); +- new_payload->vc_start_slot = old_payload->vc_start_slot; +- } + } + } + EXPORT_SYMBOL(drm_dp_mst_atomic_wait_for_dependencies); +@@ -4508,8 +4682,119 @@ void drm_dp_mst_update_slots(struct drm_dp_mst_topology_state *mst_state, uint8_ + } + EXPORT_SYMBOL(drm_dp_mst_update_slots); + ++/** ++ * drm_dp_mst_allocate_vcpi() - Allocate a virtual channel ++ * @mgr: manager for this port ++ * @port: port to allocate a virtual channel for. ++ * @pbn: payload bandwidth number to request ++ * @slots: returned number of slots for this PBN. ++ */ ++bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, ++ struct drm_dp_mst_port *port, int pbn, int slots) ++{ ++ int ret; ++ ++ if (slots < 0) ++ return false; ++ ++ port = drm_dp_mst_topology_get_port_validated(mgr, port); ++ if (!port) ++ return false; ++ ++ if (port->vcpi.vcpi > 0) { ++ drm_dbg_kms(mgr->dev, ++ "payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", ++ port->vcpi.vcpi, port->vcpi.pbn, pbn); ++ if (pbn == port->vcpi.pbn) { ++ drm_dp_mst_topology_put_port(port); ++ return true; ++ } ++ } ++ ++ ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); ++ if (ret) { ++ drm_dbg_kms(mgr->dev, "failed to init time slots=%d ret=%d\n", ++ DIV_ROUND_UP(pbn, mgr->pbn_div), ret); ++ drm_dp_mst_topology_put_port(port); ++ goto out; ++ } ++ drm_dbg_kms(mgr->dev, "initing vcpi for pbn=%d slots=%d\n", pbn, port->vcpi.num_slots); ++ ++ /* Keep port allocated until its payload has been removed */ ++ drm_dp_mst_get_port_malloc(port); ++ drm_dp_mst_topology_put_port(port); ++ return true; ++out: ++ return false; ++} ++EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi); ++ ++int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) ++{ ++ int slots = 0; ++ ++ port = drm_dp_mst_topology_get_port_validated(mgr, port); ++ if (!port) ++ return slots; ++ ++ slots = port->vcpi.num_slots; ++ drm_dp_mst_topology_put_port(port); ++ return slots; ++} ++EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); ++ ++/** ++ * drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI ++ * @mgr: manager for this port ++ * @port: unverified pointer to a port. ++ * ++ * This just resets the number of slots for the ports VCPI for later programming. ++ */ ++void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) ++{ ++ /* ++ * A port with VCPI will remain allocated until its VCPI is ++ * released, no verified ref needed ++ */ ++ ++ port->vcpi.num_slots = 0; ++} ++EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slots); ++ ++/** ++ * drm_dp_mst_deallocate_vcpi() - deallocate a VCPI ++ * @mgr: manager for this port ++ * @port: port to deallocate vcpi for ++ * ++ * This can be called unconditionally, regardless of whether ++ * drm_dp_mst_allocate_vcpi() succeeded or not. ++ */ ++void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, ++ struct drm_dp_mst_port *port) ++{ ++ bool skip; ++ ++ if (!port->vcpi.vcpi) ++ return; ++ ++ mutex_lock(&mgr->lock); ++ skip = !drm_dp_mst_port_downstream_of_branch(port, mgr->mst_primary); ++ mutex_unlock(&mgr->lock); ++ ++ if (skip) ++ return; ++ ++ drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); ++ port->vcpi.num_slots = 0; ++ port->vcpi.pbn = 0; ++ port->vcpi.aligned_pbn = 0; ++ port->vcpi.vcpi = 0; ++ drm_dp_mst_put_port_malloc(port); ++} ++EXPORT_SYMBOL(drm_dp_mst_deallocate_vcpi); ++ + static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, +- int id, u8 start_slot, u8 num_slots) ++ int id, struct drm_dp_payload *payload) + { + u8 payload_alloc[3], status; + int ret; +@@ -4519,8 +4804,8 @@ static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, + DP_PAYLOAD_TABLE_UPDATED); + + payload_alloc[0] = id; +- payload_alloc[1] = start_slot; +- payload_alloc[2] = num_slots; ++ payload_alloc[1] = payload->start_slot; ++ payload_alloc[2] = payload->num_slots; + + ret = drm_dp_dpcd_write(mgr->aux, DP_PAYLOAD_ALLOCATE_SET, payload_alloc, 3); + if (ret != 3) { +@@ -4735,9 +5020,8 @@ static void fetch_monitor_name(struct drm_dp_mst_topology_mgr *mgr, + void drm_dp_mst_dump_topology(struct seq_file *m, + struct drm_dp_mst_topology_mgr *mgr) + { +- struct drm_dp_mst_topology_state *state; +- struct drm_dp_mst_atomic_payload *payload; +- int i, ret; ++ int i; ++ struct drm_dp_mst_port *port; + + mutex_lock(&mgr->lock); + if (mgr->mst_primary) +@@ -4746,35 +5030,36 @@ void drm_dp_mst_dump_topology(struct seq_file *m, + /* dump VCPIs */ + mutex_unlock(&mgr->lock); + +- ret = drm_modeset_lock_single_interruptible(&mgr->base.lock); +- if (ret < 0) +- return; ++ mutex_lock(&mgr->payload_lock); ++ seq_printf(m, "\n*** VCPI Info ***\n"); ++ seq_printf(m, "payload_mask: %lx, vcpi_mask: %lx, max_payloads: %d\n", mgr->payload_mask, mgr->vcpi_mask, mgr->max_payloads); + +- state = to_drm_dp_mst_topology_state(mgr->base.state); +- seq_printf(m, "\n*** Atomic state info ***\n"); +- seq_printf(m, "payload_mask: %x, max_payloads: %d, start_slot: %u, pbn_div: %d\n", +- state->payload_mask, mgr->max_payloads, state->start_slot, state->pbn_div); +- +- seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | sink name |\n"); ++ seq_printf(m, "\n| idx | port # | vcp_id | # slots | sink name |\n"); + for (i = 0; i < mgr->max_payloads; i++) { +- list_for_each_entry(payload, &state->payloads, next) { ++ if (mgr->proposed_vcpis[i]) { + char name[14]; + +- if (payload->vcpi != i || payload->delete) +- continue; +- +- fetch_monitor_name(mgr, payload->port, name, sizeof(name)); +- seq_printf(m, " %5d %6d %6d %02d - %02d %5d %5s %19s\n", ++ port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi); ++ fetch_monitor_name(mgr, port, name, sizeof(name)); ++ seq_printf(m, "%10d%10d%10d%10d%20s\n", + i, +- payload->port->port_num, +- payload->vcpi, +- payload->vc_start_slot, +- payload->vc_start_slot + payload->time_slots - 1, +- payload->pbn, +- payload->dsc_enabled ? "Y" : "N", ++ port->port_num, ++ port->vcpi.vcpi, ++ port->vcpi.num_slots, + (*name != 0) ? name : "Unknown"); +- } ++ } else ++ seq_printf(m, "%6d - Unused\n", i); ++ } ++ seq_printf(m, "\n*** Payload Info ***\n"); ++ seq_printf(m, "| idx | state | start slot | # slots |\n"); ++ for (i = 0; i < mgr->max_payloads; i++) { ++ seq_printf(m, "%10d%10d%15d%10d\n", ++ i, ++ mgr->payloads[i].payload_state, ++ mgr->payloads[i].start_slot, ++ mgr->payloads[i].num_slots); + } ++ mutex_unlock(&mgr->payload_lock); + + seq_printf(m, "\n*** DPCD Info ***\n"); + mutex_lock(&mgr->lock); +@@ -4820,7 +5105,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, + + out: + mutex_unlock(&mgr->lock); +- drm_modeset_unlock(&mgr->base.lock); ++ + } + EXPORT_SYMBOL(drm_dp_mst_dump_topology); + +@@ -5141,22 +5426,9 @@ drm_dp_mst_atomic_check_payload_alloc_limits(struct drm_dp_mst_topology_mgr *mgr + mgr, mst_state, mgr->max_payloads); + return -EINVAL; + } +- +- /* Assign a VCPI */ +- if (!payload->vcpi) { +- payload->vcpi = ffz(mst_state->payload_mask) + 1; +- drm_dbg_atomic(mgr->dev, "[MST PORT:%p] assigned VCPI #%d\n", +- payload->port, payload->vcpi); +- mst_state->payload_mask |= BIT(payload->vcpi - 1); +- } + } +- +- if (!payload_count) +- mst_state->pbn_div = 0; +- +- drm_dbg_atomic(mgr->dev, "[MST MGR:%p] mst state %p TU pbn_div=%d avail=%d used=%d\n", +- mgr, mst_state, mst_state->pbn_div, avail_slots, +- mst_state->total_avail_slots - avail_slots); ++ drm_dbg_atomic(mgr->dev, "[MST MGR:%p] mst state %p TU avail=%d used=%d\n", ++ mgr, mst_state, avail_slots, mst_state->total_avail_slots - avail_slots); + + return 0; + } +@@ -5227,6 +5499,7 @@ EXPORT_SYMBOL(drm_dp_mst_add_affected_dsc_crtcs); + * @state: Pointer to the new drm_atomic_state + * @port: Pointer to the affected MST Port + * @pbn: Newly recalculated bw required for link with DSC enabled ++ * @pbn_div: Divider to calculate correct number of pbn per slot + * @enable: Boolean flag to enable or disable DSC on the port + * + * This function enables DSC on the given Port +@@ -5237,7 +5510,8 @@ EXPORT_SYMBOL(drm_dp_mst_add_affected_dsc_crtcs); + */ + int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, + struct drm_dp_mst_port *port, +- int pbn, bool enable) ++ int pbn, int pbn_div, ++ bool enable) + { + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_atomic_payload *payload; +@@ -5263,7 +5537,7 @@ int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, + } + + if (enable) { +- time_slots = drm_dp_atomic_find_time_slots(state, port->mgr, port, pbn); ++ time_slots = drm_dp_atomic_find_time_slots(state, port->mgr, port, pbn, pbn_div); + drm_dbg_atomic(state->dev, + "[MST PORT:%p] Enabling DSC flag, reallocating %d time slots on the port\n", + port, time_slots); +@@ -5276,7 +5550,6 @@ int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, + return time_slots; + } + EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); +- + /** + * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an + * atomic update is valid +@@ -5334,6 +5607,7 @@ EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs); + + /** + * drm_atomic_get_mst_topology_state: get MST topology state ++ * + * @state: global atomic state + * @mgr: MST topology manager, also the private object in this case + * +@@ -5352,31 +5626,6 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a + } + EXPORT_SYMBOL(drm_atomic_get_mst_topology_state); + +-/** +- * drm_atomic_get_new_mst_topology_state: get new MST topology state in atomic state, if any +- * @state: global atomic state +- * @mgr: MST topology manager, also the private object in this case +- * +- * This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic +- * state vtable so that the private object state returned is that of a MST +- * topology object. +- * +- * Returns: +- * +- * The MST topology state, or NULL if there's no topology state for this MST mgr +- * in the global atomic state +- */ +-struct drm_dp_mst_topology_state * +-drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_mgr *mgr) +-{ +- struct drm_private_state *priv_state = +- drm_atomic_get_new_private_obj_state(state, &mgr->base); +- +- return priv_state ? to_dp_mst_topology_state(priv_state) : NULL; +-} +-EXPORT_SYMBOL(drm_atomic_get_new_mst_topology_state); +- + /** + * drm_dp_mst_topology_mgr_init - initialise a topology manager + * @mgr: manager struct to initialise +@@ -5384,6 +5633,8 @@ EXPORT_SYMBOL(drm_atomic_get_new_mst_topology_state); + * @aux: DP helper aux channel to talk to this device + * @max_dpcd_transaction_bytes: hw specific DPCD transaction limit + * @max_payloads: maximum number of payloads this GPU can source ++ * @max_lane_count: maximum number of lanes this GPU supports ++ * @max_link_rate: maximum link rate per lane this GPU supports in kHz + * @conn_base_id: the connector object ID the MST device is connected to. + * + * Return 0 for success, or negative error code on failure +@@ -5391,12 +5642,14 @@ EXPORT_SYMBOL(drm_atomic_get_new_mst_topology_state); + int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, + struct drm_device *dev, struct drm_dp_aux *aux, + int max_dpcd_transaction_bytes, int max_payloads, ++ int max_lane_count, int max_link_rate, + int conn_base_id) + { + struct drm_dp_mst_topology_state *mst_state; + + mutex_init(&mgr->lock); + mutex_init(&mgr->qlock); ++ mutex_init(&mgr->payload_lock); + mutex_init(&mgr->delayed_destroy_lock); + mutex_init(&mgr->up_req_lock); + mutex_init(&mgr->probe_lock); +@@ -5426,7 +5679,19 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, + mgr->aux = aux; + mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes; + mgr->max_payloads = max_payloads; ++ mgr->max_lane_count = max_lane_count; ++ mgr->max_link_rate = max_link_rate; + mgr->conn_base_id = conn_base_id; ++ if (max_payloads + 1 > sizeof(mgr->payload_mask) * 8 || ++ max_payloads + 1 > sizeof(mgr->vcpi_mask) * 8) ++ return -EINVAL; ++ mgr->payloads = kcalloc(max_payloads, sizeof(struct drm_dp_payload), GFP_KERNEL); ++ if (!mgr->payloads) ++ return -ENOMEM; ++ mgr->proposed_vcpis = kcalloc(max_payloads, sizeof(struct drm_dp_vcpi *), GFP_KERNEL); ++ if (!mgr->proposed_vcpis) ++ return -ENOMEM; ++ set_bit(0, &mgr->payload_mask); + + mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL); + if (mst_state == NULL) +@@ -5459,12 +5724,19 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) + destroy_workqueue(mgr->delayed_destroy_wq); + mgr->delayed_destroy_wq = NULL; + } ++ mutex_lock(&mgr->payload_lock); ++ kfree(mgr->payloads); ++ mgr->payloads = NULL; ++ kfree(mgr->proposed_vcpis); ++ mgr->proposed_vcpis = NULL; ++ mutex_unlock(&mgr->payload_lock); + mgr->dev = NULL; + mgr->aux = NULL; + drm_atomic_private_obj_fini(&mgr->base); + mgr->funcs = NULL; + + mutex_destroy(&mgr->delayed_destroy_lock); ++ mutex_destroy(&mgr->payload_lock); + mutex_destroy(&mgr->qlock); + mutex_destroy(&mgr->lock); + mutex_destroy(&mgr->up_req_lock); +diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c +index 03604a37931c..e01a40f35284 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c +@@ -52,7 +52,6 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, + struct drm_atomic_state *state = crtc_state->uapi.state; + struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); + struct intel_dp *intel_dp = &intel_mst->primary->dp; +- struct drm_dp_mst_topology_state *mst_state; + struct intel_connector *connector = + to_intel_connector(conn_state->connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); +@@ -60,28 +59,22 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, + &crtc_state->hw.adjusted_mode; + int bpp, slots = -EINVAL; + +- mst_state = drm_atomic_get_mst_topology_state(state, &intel_dp->mst_mgr); +- if (IS_ERR(mst_state)) +- return PTR_ERR(mst_state); +- + crtc_state->lane_count = limits->max_lane_count; + crtc_state->port_clock = limits->max_rate; + +- // TODO: Handle pbn_div changes by adding a new MST helper +- if (!mst_state->pbn_div) { +- mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, +- limits->max_rate, +- limits->max_lane_count); +- } +- + for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) { ++ + crtc_state->pipe_bpp = bpp; + + crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, + crtc_state->pipe_bpp, + false); + slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, +- connector->port, crtc_state->pbn); ++ connector->port, ++ crtc_state->pbn, ++ drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, ++ crtc_state->port_clock, ++ crtc_state->lane_count)); + if (slots == -EDEADLK) + return slots; + if (slots >= 0) +@@ -364,17 +357,21 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, + struct intel_dp *intel_dp = &dig_port->dp; + struct intel_connector *connector = + to_intel_connector(old_conn_state->connector); +- struct drm_dp_mst_topology_state *mst_state = +- drm_atomic_get_mst_topology_state(&state->base, &intel_dp->mst_mgr); + struct drm_i915_private *i915 = to_i915(connector->base.dev); ++ int start_slot = intel_dp_is_uhbr(old_crtc_state) ? 0 : 1; ++ int ret; + + drm_dbg_kms(&i915->drm, "active links %d\n", + intel_dp->active_mst_links); + + intel_hdcp_disable(intel_mst->connector); + +- drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state, +- drm_atomic_get_mst_payload_state(mst_state, connector->port)); ++ drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port); ++ ++ ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr, start_slot); ++ if (ret) { ++ drm_dbg_kms(&i915->drm, "failed to update payload %d\n", ret); ++ } + + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + } +@@ -402,6 +399,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, + + intel_disable_transcoder(old_crtc_state); + ++ drm_dp_update_payload_part2(&intel_dp->mst_mgr); ++ + clear_act_sent(encoder, old_crtc_state); + + intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder), +@@ -409,6 +408,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, + + wait_for_act_sent(encoder, old_crtc_state); + ++ drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port); ++ + intel_ddi_disable_transcoder_func(old_crtc_state); + + if (DISPLAY_VER(dev_priv) >= 9) +@@ -475,8 +476,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_connector *connector = + to_intel_connector(conn_state->connector); +- struct drm_dp_mst_topology_state *mst_state = +- drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); ++ int start_slot = intel_dp_is_uhbr(pipe_config) ? 0 : 1; + int ret; + bool first_mst_stream; + +@@ -502,13 +502,16 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, + dig_port->base.pre_enable(state, &dig_port->base, + pipe_config, NULL); + ++ ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, ++ connector->port, ++ pipe_config->pbn, ++ pipe_config->dp_m_n.tu); ++ if (!ret) ++ drm_err(&dev_priv->drm, "failed to allocate vcpi\n"); ++ + intel_dp->active_mst_links++; + +- ret = drm_dp_add_payload_part1(&intel_dp->mst_mgr, mst_state, +- drm_atomic_get_mst_payload_state(mst_state, connector->port)); +- if (ret < 0) +- drm_err(&dev_priv->drm, "Failed to create MST payload for %s: %d\n", +- connector->base.name, ret); ++ ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr, start_slot); + + /* + * Before Gen 12 this is not done as part of +@@ -531,10 +534,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, + struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); + struct intel_digital_port *dig_port = intel_mst->primary; + struct intel_dp *intel_dp = &dig_port->dp; +- struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); +- struct drm_dp_mst_topology_state *mst_state = +- drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); + enum transcoder trans = pipe_config->cpu_transcoder; + + drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder); +@@ -562,8 +562,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, + + wait_for_act_sent(encoder, pipe_config); + +- drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base, +- drm_atomic_get_mst_payload_state(mst_state, connector->port)); ++ drm_dp_update_payload_part2(&intel_dp->mst_mgr); + + if (DISPLAY_VER(dev_priv) >= 14 && pipe_config->fec_enable) + intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(trans), 0, +@@ -950,6 +949,8 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id) + struct intel_dp *intel_dp = &dig_port->dp; + enum port port = dig_port->base.port; + int ret; ++ int max_source_rate = ++ intel_dp->source_rates[intel_dp->num_source_rates - 1]; + + if (!HAS_DP_MST(i915) || intel_dp_is_edp(intel_dp)) + return 0; +@@ -965,7 +966,10 @@ intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_base_id) + /* create encoders */ + intel_dp_create_fake_mst_encoders(dig_port); + ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, &i915->drm, +- &intel_dp->aux, 16, 3, conn_base_id); ++ &intel_dp->aux, 16, 3, ++ dig_port->max_lanes, ++ max_source_rate, ++ conn_base_id); + if (ret) { + intel_dp->mst_mgr.cbs = NULL; + return ret; +diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c +index 6406fd487ee5..987e02eea66a 100644 +--- a/drivers/gpu/drm/i915/display/intel_hdcp.c ++++ b/drivers/gpu/drm/i915/display/intel_hdcp.c +@@ -31,30 +31,8 @@ + + static int intel_conn_to_vcpi(struct intel_connector *connector) + { +- struct drm_dp_mst_topology_mgr *mgr; +- struct drm_dp_mst_atomic_payload *payload; +- struct drm_dp_mst_topology_state *mst_state; +- int vcpi = 0; +- + /* For HDMI this is forced to be 0x0. For DP SST also this is 0x0. */ +- if (!connector->port) +- return 0; +- mgr = connector->port->mgr; +- +- drm_modeset_lock(&mgr->base.lock, NULL); +- mst_state = to_drm_dp_mst_topology_state(mgr->base.state); +- payload = drm_atomic_get_mst_payload_state(mst_state, connector->port); +- if (drm_WARN_ON(mgr->dev, !payload)) +- goto out; +- +- vcpi = payload->vcpi; +- if (drm_WARN_ON(mgr->dev, vcpi < 0)) { +- vcpi = 0; +- goto out; +- } +-out: +- drm_modeset_unlock(&mgr->base.lock); +- return vcpi; ++ return connector->port ? connector->port->vcpi.vcpi : 0; + } + + /* +diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c +index 33c97d510999..8400a5d8ea6e 100644 +--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c ++++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c +@@ -932,7 +932,6 @@ struct nv50_msto { + struct nv50_head *head; + struct nv50_mstc *mstc; + bool disabled; +- bool enabled; + }; + + struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder) +@@ -949,36 +948,58 @@ struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder) + } + + static void +-nv50_msto_cleanup(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_state *mst_state, +- struct drm_dp_mst_topology_mgr *mgr, +- struct nv50_msto *msto) ++nv50_msto_cleanup(struct nv50_msto *msto) + { + struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); +- struct drm_dp_mst_atomic_payload *payload = +- drm_atomic_get_mst_payload_state(mst_state, msto->mstc->port); ++ ++ struct nv50_mstc *mstc = msto->mstc; ++ struct nv50_mstm *mstm = mstc->mstm; ++ ++ if (!msto->disabled) ++ return; + + NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); + +- if (msto->disabled) { +- msto->mstc = NULL; +- msto->disabled = false; +- } else if (msto->enabled) { +- drm_dp_add_payload_part2(mgr, state, payload); +- msto->enabled = false; ++ drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); ++ ++ msto->mstc = NULL; ++ msto->disabled = false; ++} ++ ++static struct drm_dp_payload * ++nv50_msto_payload(struct nv50_msto *msto) ++{ ++ struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); ++ struct nv50_mstc *mstc = msto->mstc; ++ struct nv50_mstm *mstm = mstc->mstm; ++ int vcpi = mstc->port->vcpi.vcpi, i; ++ ++ WARN_ON(!mutex_is_locked(&mstm->mgr.payload_lock)); ++ ++ NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); ++ for (i = 0; i < mstm->mgr.max_payloads; i++) { ++ struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; ++ NV_ATOMIC(drm, "%s: %d: vcpi %d start 0x%02x slots 0x%02x\n", ++ mstm->outp->base.base.name, i, payload->vcpi, ++ payload->start_slot, payload->num_slots); ++ } ++ ++ for (i = 0; i < mstm->mgr.max_payloads; i++) { ++ struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; ++ if (payload->vcpi == vcpi) ++ return payload; + } ++ ++ return NULL; + } + + static void +-nv50_msto_prepare(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_state *mst_state, +- struct drm_dp_mst_topology_mgr *mgr, +- struct nv50_msto *msto) ++nv50_msto_prepare(struct nv50_msto *msto) + { + struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; +- struct drm_dp_mst_atomic_payload *payload; ++ struct drm_dp_payload *payload = NULL; + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_sor_dp_mst_vcpi_v0 vcpi; +@@ -990,27 +1011,28 @@ nv50_msto_prepare(struct drm_atomic_state *state, + (0x0100 << msto->head->base.index), + }; + ++ mutex_lock(&mstm->mgr.payload_lock); ++ + NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); + +- payload = drm_atomic_get_mst_payload_state(mst_state, mstc->port); ++ if (mstc->port->vcpi.vcpi > 0) ++ payload = nv50_msto_payload(msto); + +- // TODO: Figure out if we want to do a better job of handling VCPI allocation failures here? +- if (msto->disabled) { +- drm_dp_remove_payload(mgr, mst_state, payload); +- } else { +- if (msto->enabled) +- drm_dp_add_payload_part1(mgr, mst_state, payload); ++ if (payload) { ++ NV_ATOMIC(drm, "%s: %s: %02x %02x %04x %04x\n", ++ msto->encoder.name, msto->head->base.base.name, ++ payload->start_slot, payload->num_slots, ++ mstc->port->vcpi.pbn, mstc->port->vcpi.aligned_pbn); + +- args.vcpi.start_slot = payload->vc_start_slot; +- args.vcpi.num_slots = payload->time_slots; ++ args.vcpi.start_slot = payload->start_slot; ++ args.vcpi.num_slots = payload->num_slots; + args.vcpi.pbn = payload->pbn; +- args.vcpi.aligned_pbn = payload->time_slots * mst_state->pbn_div; +- } ++ } else { ++ NV_ATOMIC(drm, "%s: %s: %02x %02x %04x %04x\n", ++ msto->encoder.name, msto->head->base.base.name, 0, 0, 0, 0); ++ } + +- NV_ATOMIC(drm, "%s: %s: %02x %02x %04x %04x\n", +- msto->encoder.name, msto->head->base.base.name, +- args.vcpi.start_slot, args.vcpi.num_slots, +- args.vcpi.pbn, args.vcpi.aligned_pbn); ++ mutex_unlock(&mstm->mgr.payload_lock); + + nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); + } +@@ -1022,7 +1044,6 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, + { + struct drm_atomic_state *state = crtc_state->state; + struct drm_connector *connector = conn_state->connector; +- struct drm_dp_mst_topology_state *mst_state; + struct nv50_mstc *mstc = nv50_mstc(connector); + struct nv50_mstm *mstm = mstc->mstm; + struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); +@@ -1050,18 +1071,8 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, + false); + } + +- mst_state = drm_atomic_get_mst_topology_state(state, &mstm->mgr); +- if (IS_ERR(mst_state)) +- return PTR_ERR(mst_state); +- +- if (!mst_state->pbn_div) { +- struct nouveau_encoder *outp = mstc->mstm->outp; +- +- mst_state->pbn_div = drm_dp_get_vc_payload_bw(&mstm->mgr, +- outp->dp.link_bw, outp->dp.link_nr); +- } +- +- slots = drm_dp_atomic_find_time_slots(state, &mstm->mgr, mstc->port, asyh->dp.pbn); ++ slots = drm_dp_atomic_find_time_slots(state, &mstm->mgr, mstc->port, ++ asyh->dp.pbn, 0); + if (slots < 0) + return slots; + +@@ -1093,6 +1104,7 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + u8 proto; ++ bool r; + + drm_connector_list_iter_begin(encoder->dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { +@@ -1107,6 +1119,10 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st + if (WARN_ON(!mstc)) + return; + ++ r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, asyh->dp.pbn, asyh->dp.tu); ++ if (!r) ++ DRM_DEBUG_KMS("Failed to allocate VCPI\n"); ++ + if (!mstm->links++) + nv50_outp_acquire(mstm->outp, false /*XXX: MST audio.*/); + +@@ -1119,7 +1135,6 @@ nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st + nv50_dp_bpc_to_depth(asyh->or.bpc)); + + msto->mstc = mstc; +- msto->enabled = true; + mstm->modified = true; + } + +@@ -1130,6 +1145,8 @@ nv50_msto_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *s + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; + ++ drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); ++ + mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); + mstm->modified = true; + if (!--mstm->links) +@@ -1349,9 +1366,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, + } + + static void +-nv50_mstm_cleanup(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_state *mst_state, +- struct nv50_mstm *mstm) ++nv50_mstm_cleanup(struct nv50_mstm *mstm) + { + struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); + struct drm_encoder *encoder; +@@ -1359,12 +1374,14 @@ nv50_mstm_cleanup(struct drm_atomic_state *state, + NV_ATOMIC(drm, "%s: mstm cleanup\n", mstm->outp->base.base.name); + drm_dp_check_act_status(&mstm->mgr); + ++ drm_dp_update_payload_part2(&mstm->mgr); ++ + drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { + if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { + struct nv50_msto *msto = nv50_msto(encoder); + struct nv50_mstc *mstc = msto->mstc; + if (mstc && mstc->mstm == mstm) +- nv50_msto_cleanup(state, mst_state, &mstm->mgr, msto); ++ nv50_msto_cleanup(msto); + } + } + +@@ -1372,34 +1389,20 @@ nv50_mstm_cleanup(struct drm_atomic_state *state, + } + + static void +-nv50_mstm_prepare(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_state *mst_state, +- struct nv50_mstm *mstm) ++nv50_mstm_prepare(struct nv50_mstm *mstm) + { + struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); + struct drm_encoder *encoder; + + NV_ATOMIC(drm, "%s: mstm prepare\n", mstm->outp->base.base.name); ++ drm_dp_update_payload_part1(&mstm->mgr, 1); + +- /* Disable payloads first */ +- drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { +- if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { +- struct nv50_msto *msto = nv50_msto(encoder); +- struct nv50_mstc *mstc = msto->mstc; +- if (mstc && mstc->mstm == mstm && msto->disabled) +- nv50_msto_prepare(state, mst_state, &mstm->mgr, msto); +- } +- } +- +- /* Add payloads for new heads, while also updating the start slots of any unmodified (but +- * active) heads that may have had their VC slots shifted left after the previous step +- */ + drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { + if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { + struct nv50_msto *msto = nv50_msto(encoder); + struct nv50_mstc *mstc = msto->mstc; +- if (mstc && mstc->mstm == mstm && !msto->disabled) +- nv50_msto_prepare(state, mst_state, &mstm->mgr, msto); ++ if (mstc && mstc->mstm == mstm) ++ nv50_msto_prepare(msto); + } + } + +@@ -1596,7 +1599,9 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, + mstm->mgr.cbs = &nv50_mstm; + + ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max, +- max_payloads, conn_base_id); ++ max_payloads, outp->dcb->dpconf.link_nr, ++ drm_dp_bw_code_to_link_rate(outp->dcb->dpconf.link_bw), ++ conn_base_id); + if (ret) + return ret; + +@@ -2048,20 +2053,20 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) + static void + nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) + { +- struct drm_dp_mst_topology_mgr *mgr; +- struct drm_dp_mst_topology_state *mst_state; + struct nouveau_drm *drm = nouveau_drm(state->dev); + struct nv50_disp *disp = nv50_disp(drm->dev); + struct nv50_core *core = disp->core; + struct nv50_mstm *mstm; +- int i; ++ struct drm_encoder *encoder; + + NV_ATOMIC(drm, "commit core %08x\n", interlock[NV50_DISP_INTERLOCK_BASE]); + +- for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { +- mstm = nv50_mstm(mgr); +- if (mstm->modified) +- nv50_mstm_prepare(state, mst_state, mstm); ++ drm_for_each_encoder(encoder, drm->dev) { ++ if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { ++ mstm = nouveau_encoder(encoder)->dp.mstm; ++ if (mstm && mstm->modified) ++ nv50_mstm_prepare(mstm); ++ } + } + + core->func->ntfy_init(disp->sync, NV50_DISP_CORE_NTFY); +@@ -2070,10 +2075,12 @@ nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) + disp->core->chan.base.device)) + NV_ERROR(drm, "core notifier timeout\n"); + +- for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { +- mstm = nv50_mstm(mgr); +- if (mstm->modified) +- nv50_mstm_cleanup(state, mst_state, mstm); ++ drm_for_each_encoder(encoder, drm->dev) { ++ if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { ++ mstm = nouveau_encoder(encoder)->dp.mstm; ++ if (mstm && mstm->modified) ++ nv50_mstm_cleanup(mstm); ++ } + } + } + +diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h +index 41fd8352ab65..1d2f77835de5 100644 +--- a/include/drm/display/drm_dp_mst_helper.h ++++ b/include/drm/display/drm_dp_mst_helper.h +@@ -48,6 +48,20 @@ struct drm_dp_mst_topology_ref_history { + + struct drm_dp_mst_branch; + ++/** ++ * struct drm_dp_vcpi - Virtual Channel Payload Identifier ++ * @vcpi: Virtual channel ID. ++ * @pbn: Payload Bandwidth Number for this channel ++ * @aligned_pbn: PBN aligned with slot size ++ * @num_slots: number of slots for this PBN ++ */ ++struct drm_dp_vcpi { ++ int vcpi; ++ int pbn; ++ int aligned_pbn; ++ int num_slots; ++}; ++ + /** + * struct drm_dp_mst_port - MST port + * @port_num: port number +@@ -131,6 +145,7 @@ struct drm_dp_mst_port { + struct drm_dp_aux *passthrough_aux; + struct drm_dp_mst_branch *parent; + ++ struct drm_dp_vcpi vcpi; + struct drm_connector *connector; + struct drm_dp_mst_topology_mgr *mgr; + +@@ -515,6 +530,20 @@ struct drm_dp_mst_topology_cbs { + void (*poll_hpd_irq)(struct drm_dp_mst_topology_mgr *mgr); + }; + ++#define DP_MAX_PAYLOAD (sizeof(unsigned long) * 8) ++ ++#define DP_PAYLOAD_LOCAL 1 ++#define DP_PAYLOAD_REMOTE 2 ++#define DP_PAYLOAD_DELETE_LOCAL 3 ++ ++struct drm_dp_payload { ++ int payload_state; ++ int start_slot; ++ int num_slots; ++ int vcpi; ++ int pbn; ++}; ++ + #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) + + /** +@@ -527,34 +556,6 @@ struct drm_dp_mst_atomic_payload { + /** @port: The MST port assigned to this payload */ + struct drm_dp_mst_port *port; + +- /** +- * @vc_start_slot: The time slot that this payload starts on. Because payload start slots +- * can't be determined ahead of time, the contents of this value are UNDEFINED at atomic +- * check time. This shouldn't usually matter, as the start slot should never be relevant for +- * atomic state computations. +- * +- * Since this value is determined at commit time instead of check time, this value is +- * protected by the MST helpers ensuring that async commits operating on the given topology +- * never run in parallel. In the event that a driver does need to read this value (e.g. to +- * inform hardware of the starting timeslot for a payload), the driver may either: +- * +- * * Read this field during the atomic commit after +- * drm_dp_mst_atomic_wait_for_dependencies() has been called, which will ensure the +- * previous MST states payload start slots have been copied over to the new state. Note +- * that a new start slot won't be assigned/removed from this payload until +- * drm_dp_add_payload_part1()/drm_dp_remove_payload() have been called. +- * * Acquire the MST modesetting lock, and then wait for any pending MST-related commits to +- * get committed to hardware by calling drm_crtc_commit_wait() on each of the +- * &drm_crtc_commit structs in &drm_dp_mst_topology_state.commit_deps. +- * +- * If neither of the two above solutions suffice (e.g. the driver needs to read the start +- * slot in the middle of an atomic commit without waiting for some reason), then drivers +- * should cache this value themselves after changing payloads. +- */ +- s8 vc_start_slot; +- +- /** @vcpi: The Virtual Channel Payload Identifier */ +- u8 vcpi; + /** + * @time_slots: + * The number of timeslots allocated to this payload from the source DP Tx to +@@ -582,6 +583,8 @@ struct drm_dp_mst_topology_state { + /** @base: Base private state for atomic */ + struct drm_private_state base; + ++ /** @payloads: The list of payloads being created/destroyed in this state */ ++ struct list_head payloads; + /** @mgr: The topology manager */ + struct drm_dp_mst_topology_mgr *mgr; + +@@ -598,21 +601,10 @@ struct drm_dp_mst_topology_state { + /** @num_commit_deps: The number of CRTC commits in @commit_deps */ + size_t num_commit_deps; + +- /** @payload_mask: A bitmask of allocated VCPIs, used for VCPI assignments */ +- u32 payload_mask; +- /** @payloads: The list of payloads being created/destroyed in this state */ +- struct list_head payloads; +- + /** @total_avail_slots: The total number of slots this topology can handle (63 or 64) */ + u8 total_avail_slots; + /** @start_slot: The first usable time slot in this topology (1 or 0) */ + u8 start_slot; +- +- /** +- * @pbn_div: The current PBN divisor for this topology. The driver is expected to fill this +- * out itself. +- */ +- int pbn_div; + }; + + #define to_dp_mst_topology_mgr(x) container_of(x, struct drm_dp_mst_topology_mgr, base) +@@ -652,6 +644,14 @@ struct drm_dp_mst_topology_mgr { + * @max_payloads: maximum number of payloads the GPU can generate. + */ + int max_payloads; ++ /** ++ * @max_lane_count: maximum number of lanes the GPU can drive. ++ */ ++ int max_lane_count; ++ /** ++ * @max_link_rate: maximum link rate per lane GPU can output, in kHz. ++ */ ++ int max_link_rate; + /** + * @conn_base_id: DRM connector ID this mgr is connected to. Only used + * to build the MST connector path value. +@@ -694,20 +694,6 @@ struct drm_dp_mst_topology_mgr { + */ + bool payload_id_table_cleared : 1; + +- /** +- * @payload_count: The number of currently active payloads in hardware. This value is only +- * intended to be used internally by MST helpers for payload tracking, and is only safe to +- * read/write from the atomic commit (not check) context. +- */ +- u8 payload_count; +- +- /** +- * @next_start_slot: The starting timeslot to use for new VC payloads. This value is used +- * internally by MST helpers for payload tracking, and is only safe to read/write from the +- * atomic commit (not check) context. +- */ +- u8 next_start_slot; +- + /** + * @mst_primary: Pointer to the primary/first branch device. + */ +@@ -721,6 +707,10 @@ struct drm_dp_mst_topology_mgr { + * @sink_count: Sink count from DEVICE_SERVICE_IRQ_VECTOR_ESI0. + */ + u8 sink_count; ++ /** ++ * @pbn_div: PBN to slots divisor. ++ */ ++ int pbn_div; + + /** + * @funcs: Atomic helper callbacks +@@ -737,6 +727,32 @@ struct drm_dp_mst_topology_mgr { + */ + struct list_head tx_msg_downq; + ++ /** ++ * @payload_lock: Protect payload information. ++ */ ++ struct mutex payload_lock; ++ /** ++ * @proposed_vcpis: Array of pointers for the new VCPI allocation. The ++ * VCPI structure itself is &drm_dp_mst_port.vcpi, and the size of ++ * this array is determined by @max_payloads. ++ */ ++ struct drm_dp_vcpi **proposed_vcpis; ++ /** ++ * @payloads: Array of payloads. The size of this array is determined ++ * by @max_payloads. ++ */ ++ struct drm_dp_payload *payloads; ++ /** ++ * @payload_mask: Elements of @payloads actually in use. Since ++ * reallocation of active outputs isn't possible gaps can be created by ++ * disabling outputs out of order compared to how they've been enabled. ++ */ ++ unsigned long payload_mask; ++ /** ++ * @vcpi_mask: Similar to @payload_mask, but for @proposed_vcpis. ++ */ ++ unsigned long vcpi_mask; ++ + /** + * @tx_waitq: Wait to queue stall for the tx worker. + */ +@@ -808,7 +824,9 @@ struct drm_dp_mst_topology_mgr { + int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, + struct drm_device *dev, struct drm_dp_aux *aux, + int max_dpcd_transaction_bytes, +- int max_payloads, int conn_base_id); ++ int max_payloads, ++ int max_lane_count, int max_link_rate, ++ int conn_base_id); + + void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr); + +@@ -831,17 +849,28 @@ int drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, + + int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc); + ++bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, ++ struct drm_dp_mst_port *port, int pbn, int slots); ++ ++int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); ++ ++ ++void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); ++ + void drm_dp_mst_update_slots(struct drm_dp_mst_topology_state *mst_state, uint8_t link_encoding_cap); + +-int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_topology_state *mst_state, +- struct drm_dp_mst_atomic_payload *payload); +-int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_atomic_state *state, +- struct drm_dp_mst_atomic_payload *payload); +-void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_topology_state *mst_state, +- struct drm_dp_mst_atomic_payload *payload); ++void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, ++ struct drm_dp_mst_port *port); ++ ++ ++int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, ++ int pbn); ++ ++ ++int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr, int start_slot); ++ ++ ++int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr); + + int drm_dp_check_act_status(struct drm_dp_mst_topology_mgr *mgr); + +@@ -863,22 +892,17 @@ int drm_dp_mst_connector_late_register(struct drm_connector *connector, + void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, + struct drm_dp_mst_port *port); + +-struct drm_dp_mst_topology_state * +-drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_mgr *mgr); +-struct drm_dp_mst_topology_state * +-drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state, +- struct drm_dp_mst_topology_mgr *mgr); +-struct drm_dp_mst_atomic_payload * +-drm_atomic_get_mst_payload_state(struct drm_dp_mst_topology_state *state, +- struct drm_dp_mst_port *port); ++struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, ++ struct drm_dp_mst_topology_mgr *mgr); + int __must_check + drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, +- struct drm_dp_mst_port *port, int pbn); ++ struct drm_dp_mst_port *port, int pbn, ++ int pbn_div); + int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, + struct drm_dp_mst_port *port, +- int pbn, bool enable); ++ int pbn, int pbn_div, ++ bool enable); + int __must_check + drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr); +@@ -902,12 +926,6 @@ void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); + + struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port); + +-static inline struct drm_dp_mst_topology_state * +-to_drm_dp_mst_topology_state(struct drm_private_state *state) +-{ +- return container_of(state, struct drm_dp_mst_topology_state, base); +-} +- + extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; + + /** +-- +2.39.0 + diff --git a/0004-netfilter-nft_payload-incorrect-arithmetics-when-fet.patch b/0004-netfilter-nft_payload-incorrect-arithmetics-when-fet.patch new file mode 100644 index 000000000000..be3d2a892751 --- /dev/null +++ b/0004-netfilter-nft_payload-incorrect-arithmetics-when-fet.patch @@ -0,0 +1,41 @@ +From 07fa6df737871f5e491ec70f499963aedd679f2a Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso <pablo@netfilter.org> +Date: Wed, 11 Jan 2023 17:07:33 +0100 +Subject: [PATCH 4/5] netfilter: nft_payload: incorrect arithmetics when + fetching VLAN header bits + +commit 696e1a48b1a1b01edad542a1ef293665864a4dd0 upstream. + +If the offset + length goes over the ethernet + vlan header, then the +length is adjusted to copy the bytes that are within the boundaries of +the vlan_ethhdr scratchpad area. The remaining bytes beyond ethernet + +vlan header are copied directly from the skbuff data area. + +Fix incorrect arithmetic operator: subtract, not add, the size of the +vlan header in case of double-tagged packets to adjust the length +accordingly to address CVE-2023-0179. + +Reported-by: Davide Ornaghi <d.ornaghi97@gmail.com> +Fixes: f6ae9f120dad ("netfilter: nft_payload: add C-VLAN support") +Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/netfilter/nft_payload.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c +index 4edd899aeb9b..d7de2ecb287e 100644 +--- a/net/netfilter/nft_payload.c ++++ b/net/netfilter/nft_payload.c +@@ -62,7 +62,7 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len) + return false; + + if (offset + len > VLAN_ETH_HLEN + vlan_hlen) +- ethlen -= offset + len - VLAN_ETH_HLEN + vlan_hlen; ++ ethlen -= offset + len - VLAN_ETH_HLEN - vlan_hlen; + + memcpy(dst_u8, vlanh + offset - vlan_hlen, ethlen); + +-- +2.39.0 + @@ -68,8 +68,8 @@ _subarch= ### IMPORTANT: Do no edit below this line unless you know what you're doing pkgbase=linux-ck -pkgver=6.1.5 -pkgrel=2 +pkgver=6.1.6 +pkgrel=1 arch=(x86_64) url="https://wiki.archlinux.org/index.php/Linux-ck" license=(GPL2) @@ -91,19 +91,23 @@ source=( "more-uarches-$_gcc_more_v.tar.gz::https://github.com/graysky2/kernel_compiler_patch/archive/$_gcc_more_v.tar.gz" "ck-hrtimer-$_commit.tar.gz::https://github.com/graysky2/linux-patches/archive/$_commit.tar.gz" 0001-ZEN-Add-sysctl-and-CONFIG-to-disallow-unprivileged-C.patch - 0002-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch + 0002-docs-Fix-the-docs-build-with-Sphinx-6.0.patch + 0003-Revert-drm-display-dp_mst-Move-all-payload-info-into.patch + 0004-netfilter-nft_payload-incorrect-arithmetics-when-fet.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds '647F28654894E3BD457199BE38DBBDC86092693E' # Greg Kroah-Hartman ) -sha256sums=('bc7f6d9a8a8bbe9a723e82346bba94b58d926f78bfba106b21e041e0290076fc' +sha256sums=('3e4d8e561da5703a205ae8d7b2bed6c5c64fc4299eebcbfd20481e63b57d5ee3' 'SKIP' - '0571ea17a2e38458096b679418197bbea8c414388f628d122517f3a1f3a31b3a' + '1efa33aea067fa920880ef7fef3ec82f8d4cde21213eda34ac6534ca6879fca0' 'f1d586e111932890ad5e0df15d092fb9b3f87bae4ea17812aae9b0ec98fe2db0' '6d3b9cb4639c1c5eb4e2697aed0dbffa5b4a37d63a0861dec8315dd052723e0e' - '00c7b866ba5393639d5ca2349883909ad6b1bedf6091e857c83f208e0838479c' - '601a923873d2d598d5a615b09c2863aa8402ced6da24215d2b25eac3c4987ed3') + 'e804772a555fcd60140e0ea35f8269c57d7c32d3440f0ff06c044b21a8f4681e' + 'a46f8d26cb20397b06812af7d56800a0994fcd263262e3ca5f22dc2247c2b623' + '59c4479ecd93ecc3c6ca452f24e4ec8bc92fec8a99109222e6ac457fc1ea5d12' + '05feb34e7ab03085dd7d4ae252bea419a7d13048b081451e1e23b31dcc2b58db') prepare() { cd linux-${pkgver} @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.1.0-arch1 Kernel Configuration +# Linux/x86 6.1.6-arch1 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (GCC) 12.2.0" CONFIG_CC_IS_GCC=y @@ -206,6 +206,7 @@ CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y CONFIG_CC_HAS_INT128=y CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" +CONFIG_GCC11_NO_ARRAY_BOUNDS=y CONFIG_GCC12_NO_ARRAY_BOUNDS=y CONFIG_CC_NO_ARRAY_BOUNDS=y CONFIG_ARCH_SUPPORTS_INT128=y |