--- /dev/null
+From 9c4f59ea3f865693150edf0c91d1cc6b451360dd Mon Sep 17 00:00:00 2001
+From: Yifan Zhang <yifan1.zhang@amd.com>
+Date: Fri, 11 Feb 2022 17:58:08 +0800
+Subject: drm/amd/pm: correct the sequence of sending gpu reset msg
+
+From: Yifan Zhang <yifan1.zhang@amd.com>
+
+commit 9c4f59ea3f865693150edf0c91d1cc6b451360dd upstream.
+
+the 2nd parameter should be smu msg type rather than asic msg index.
+
+Fixes: 7d38d9dc4ecc ("drm/amdgpu: add mode2 reset support for yellow carp")
+Signed-off-by: Yifan Zhang <yifan1.zhang@amd.com>
+Acked-by: Aaron Liu <aaron.liu@amd.com>
+Reviewed-by: Huang Rui <ray.huang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
+@@ -282,14 +282,9 @@ static int yellow_carp_post_smu_init(str
+
+ static int yellow_carp_mode_reset(struct smu_context *smu, int type)
+ {
+- int ret = 0, index = 0;
++ int ret = 0;
+
+- index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
+- SMU_MSG_GfxDeviceDriverReset);
+- if (index < 0)
+- return index == -EACCES ? 0 : index;
+-
+- ret = smu_cmn_send_smc_msg_with_param(smu, (uint16_t)index, type, NULL);
++ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, type, NULL);
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to mode reset!\n");
+
--- /dev/null
+From f8f4e2a518347063179def4e64580b2d28233d03 Mon Sep 17 00:00:00 2001
+From: Rajib Mahapatra <rajib.mahapatra@amd.com>
+Date: Thu, 10 Feb 2022 18:46:40 +0530
+Subject: drm/amdgpu: skipping SDMA hw_init and hw_fini for S0ix.
+
+From: Rajib Mahapatra <rajib.mahapatra@amd.com>
+
+commit f8f4e2a518347063179def4e64580b2d28233d03 upstream.
+
+[Why]
+SDMA ring buffer test failed if suspend is aborted during
+S0i3 resume.
+
+[How]
+If suspend is aborted for some reason during S0i3 resume
+cycle, it follows SDMA ring test failing and errors in amdgpu
+resume. For RN/CZN/Picasso, SMU saves and restores SDMA
+registers during S0ix cycle. So, skipping SDMA suspend and
+resume from driver solves the issue. This time, the system
+is able to resume gracefully even the suspend is aborted.
+
+Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Rajib Mahapatra <rajib.mahapatra@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+@@ -2057,6 +2057,10 @@ static int sdma_v4_0_suspend(void *handl
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ /* SMU saves SDMA state for us */
++ if (adev->in_s0ix)
++ return 0;
++
+ return sdma_v4_0_hw_fini(adev);
+ }
+
+@@ -2064,6 +2068,10 @@ static int sdma_v4_0_resume(void *handle
+ {
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
++ /* SMU restores SDMA state for us */
++ if (adev->in_s0ix)
++ return 0;
++
+ return sdma_v4_0_hw_init(adev);
+ }
+
--- /dev/null
+From 439cf34c8e0a8a33d8c15a31be1b7423426bc765 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
+Date: Wed, 9 Feb 2022 11:19:27 +0200
+Subject: drm/atomic: Don't pollute crtc_state->mode_blob with error pointers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ville Syrjälä <ville.syrjala@linux.intel.com>
+
+commit 439cf34c8e0a8a33d8c15a31be1b7423426bc765 upstream.
+
+Make sure we don't assign an error pointer to crtc_state->mode_blob
+as that will break all kinds of places that assume either NULL or a
+valid pointer (eg. drm_property_blob_put()).
+
+Cc: stable@vger.kernel.org
+Reported-by: fuyufan <fuyufan@huawei.com>
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220209091928.14766-1-ville.syrjala@linux.intel.com
+Acked-by: Maxime Ripard <maxime@cerno.tech>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_atomic_uapi.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/gpu/drm/drm_atomic_uapi.c
++++ b/drivers/gpu/drm/drm_atomic_uapi.c
+@@ -76,15 +76,17 @@ int drm_atomic_set_mode_for_crtc(struct
+ state->mode_blob = NULL;
+
+ if (mode) {
++ struct drm_property_blob *blob;
++
+ drm_mode_convert_to_umode(&umode, mode);
+- state->mode_blob =
+- drm_property_create_blob(state->crtc->dev,
+- sizeof(umode),
+- &umode);
+- if (IS_ERR(state->mode_blob))
+- return PTR_ERR(state->mode_blob);
++ blob = drm_property_create_blob(crtc->dev,
++ sizeof(umode), &umode);
++ if (IS_ERR(blob))
++ return PTR_ERR(blob);
+
+ drm_mode_copy(&state->mode, mode);
++
++ state->mode_blob = blob;
+ state->enable = true;
+ drm_dbg_atomic(crtc->dev,
+ "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
--- /dev/null
+From 698bef8ff5d2edea5d1c9d6e5adf1bfed1e8a106 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
+Date: Mon, 7 Feb 2022 15:26:59 +0200
+Subject: drm/i915: Fix dbuf slice config lookup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ville Syrjälä <ville.syrjala@linux.intel.com>
+
+commit 698bef8ff5d2edea5d1c9d6e5adf1bfed1e8a106 upstream.
+
+Apparently I totally fumbled the loop condition when I
+removed the ARRAY_SIZE() stuff from the dbuf slice config
+lookup. Comparing the loop index with the active_pipes bitmask
+is utter nonsense, what we want to do is check to see if the
+mask is zero or not.
+
+Note that the code actually ended up working correctly despite
+the fumble, up until commit eef173954432 ("drm/i915: Allow
+!join_mbus cases for adlp+ dbuf configuration") when things
+broke for real.
+
+Cc: stable@vger.kernel.org
+Fixes: 05e8155afe35 ("drm/i915: Use a sentinel to terminate the dbuf slice arrays")
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220207132700.481-1-ville.syrjala@linux.intel.com
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+(cherry picked from commit a28fde308c3c1c174249ff9559b57f24e6850086)
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/intel_pm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -4860,7 +4860,7 @@ static u8 compute_dbuf_slices(enum pipe
+ {
+ int i;
+
+- for (i = 0; i < dbuf_slices[i].active_pipes; i++) {
++ for (i = 0; dbuf_slices[i].active_pipes != 0; i++) {
+ if (dbuf_slices[i].active_pipes == active_pipes &&
+ dbuf_slices[i].join_mbus == join_mbus)
+ return dbuf_slices[i].dbuf_mask[pipe];
--- /dev/null
+From 8d9d2a723d64b650f2e6423024ccb4a33f0cdc40 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
+Date: Mon, 7 Feb 2022 15:27:00 +0200
+Subject: drm/i915: Fix mbus join config lookup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ville Syrjälä <ville.syrjala@linux.intel.com>
+
+commit 8d9d2a723d64b650f2e6423024ccb4a33f0cdc40 upstream.
+
+The bogus loop from compute_dbuf_slices() was copied into
+check_mbus_joined() as well. So this lookup is wrong as well.
+Fix it.
+
+Cc: stable@vger.kernel.org
+Fixes: f4dc00863226 ("drm/i915/adl_p: MBUS programming")
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220207132700.481-2-ville.syrjala@linux.intel.com
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+(cherry picked from commit 053f2b85631316a9226f6340c1c0fd95634f7a5b)
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/intel_pm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -4843,7 +4843,7 @@ static bool check_mbus_joined(u8 active_
+ {
+ int i;
+
+- for (i = 0; i < dbuf_slices[i].active_pipes; i++) {
++ for (i = 0; dbuf_slices[i].active_pipes != 0; i++) {
+ if (dbuf_slices[i].active_pipes == active_pipes)
+ return dbuf_slices[i].join_mbus;
+ }
--- /dev/null
+From ea958422291de248b9e2eaaeea36004e84b64043 Mon Sep 17 00:00:00 2001
+From: Jani Nikula <jani.nikula@intel.com>
+Date: Thu, 10 Feb 2022 12:36:42 +0200
+Subject: drm/i915/opregion: check port number bounds for SWSCI display power state
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jani Nikula <jani.nikula@intel.com>
+
+commit ea958422291de248b9e2eaaeea36004e84b64043 upstream.
+
+The mapping from enum port to whatever port numbering scheme is used by
+the SWSCI Display Power State Notification is odd, and the memory of it
+has faded. In any case, the parameter only has space for ports numbered
+[0..4], and UBSAN reports bit shift beyond it when the platform has port
+F or more.
+
+Since the SWSCI functionality is supposed to be obsolete for new
+platforms (i.e. ones that might have port F or more), just bail out
+early if the mapped and mangled port number is beyond what the Display
+Power State Notification can support.
+
+Fixes: 9c4b0a683193 ("drm/i915: add opregion function to notify bios of encoder enable/disable")
+Cc: <stable@vger.kernel.org> # v3.13+
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Lucas De Marchi <lucas.demarchi@intel.com>
+Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/4800
+Signed-off-by: Jani Nikula <jani.nikula@intel.com>
+Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/cc363f42d6b5a5932b6d218fefcc8bdfb15dbbe5.1644489329.git.jani.nikula@intel.com
+(cherry picked from commit 24a644ebbfd3b13cda702f98907f9dd123e34bf9)
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/display/intel_opregion.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/drivers/gpu/drm/i915/display/intel_opregion.c
++++ b/drivers/gpu/drm/i915/display/intel_opregion.c
+@@ -360,6 +360,21 @@ int intel_opregion_notify_encoder(struct
+ port++;
+ }
+
++ /*
++ * The port numbering and mapping here is bizarre. The now-obsolete
++ * swsci spec supports ports numbered [0..4]. Port E is handled as a
++ * special case, but port F and beyond are not. The functionality is
++ * supposed to be obsolete for new platforms. Just bail out if the port
++ * number is out of bounds after mapping.
++ */
++ if (port > 4) {
++ drm_dbg_kms(&dev_priv->drm,
++ "[ENCODER:%d:%s] port %c (index %u) out of bounds for display power state notification\n",
++ intel_encoder->base.base.id, intel_encoder->base.name,
++ port_name(intel_encoder->port), port);
++ return -EINVAL;
++ }
++
+ if (!enable)
+ parm |= 4 << 8;
+
--- /dev/null
+From 647474b8d980256b26b1cd112d7333a4dbd4260a Mon Sep 17 00:00:00 2001
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Date: Mon, 31 Jan 2022 09:55:20 +0100
+Subject: drm/mediatek: mtk_dsi: Avoid EPROBE_DEFER loop with external bridge
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+commit 647474b8d980256b26b1cd112d7333a4dbd4260a upstream.
+
+DRM bridge drivers are now attaching their DSI device at probe time,
+which requires us to register our DSI host in order to let the bridge
+to probe: this recently started producing an endless -EPROBE_DEFER
+loop on some machines that are using external bridges, like the
+parade-ps8640, found on the ACER Chromebook R13.
+
+Now that the DSI hosts/devices probe sequence is documented, we can
+do adjustments to the mtk_dsi driver as to both fix now and make sure
+to avoid this situation in the future: for this, following what is
+documented in drm_bridge.c, move the mtk_dsi component_add() to the
+mtk_dsi_ops.attach callback and delete it in the detach callback;
+keeping in mind that we are registering a drm_bridge for our DSI,
+which is only used/attached if the DSI Host is bound, it wouldn't
+make sense to keep adding our bridge at probe time (as it would
+be useless to have it if mtk_dsi_ops.attach() fails!), so also move
+that one to the dsi host attach function (and remove it in detach).
+
+Cc: <stable@vger.kernel.org> # 5.15.x
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com>
+Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
+Tested-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/mediatek/mtk_dsi.c | 167 ++++++++++++++++++-------------------
+ 1 file changed, 84 insertions(+), 83 deletions(-)
+
+--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
+@@ -786,18 +786,101 @@ void mtk_dsi_ddp_stop(struct device *dev
+ mtk_dsi_poweroff(dsi);
+ }
+
++static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
++{
++ int ret;
++
++ ret = drm_simple_encoder_init(drm, &dsi->encoder,
++ DRM_MODE_ENCODER_DSI);
++ if (ret) {
++ DRM_ERROR("Failed to encoder init to drm\n");
++ return ret;
++ }
++
++ dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev);
++
++ ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
++ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
++ if (ret)
++ goto err_cleanup_encoder;
++
++ dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder);
++ if (IS_ERR(dsi->connector)) {
++ DRM_ERROR("Unable to create bridge connector\n");
++ ret = PTR_ERR(dsi->connector);
++ goto err_cleanup_encoder;
++ }
++ drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
++
++ return 0;
++
++err_cleanup_encoder:
++ drm_encoder_cleanup(&dsi->encoder);
++ return ret;
++}
++
++static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
++{
++ int ret;
++ struct drm_device *drm = data;
++ struct mtk_dsi *dsi = dev_get_drvdata(dev);
++
++ ret = mtk_dsi_encoder_init(drm, dsi);
++ if (ret)
++ return ret;
++
++ return device_reset_optional(dev);
++}
++
++static void mtk_dsi_unbind(struct device *dev, struct device *master,
++ void *data)
++{
++ struct mtk_dsi *dsi = dev_get_drvdata(dev);
++
++ drm_encoder_cleanup(&dsi->encoder);
++}
++
++static const struct component_ops mtk_dsi_component_ops = {
++ .bind = mtk_dsi_bind,
++ .unbind = mtk_dsi_unbind,
++};
++
+ static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+ {
+ struct mtk_dsi *dsi = host_to_dsi(host);
++ struct device *dev = host->dev;
++ int ret;
+
+ dsi->lanes = device->lanes;
+ dsi->format = device->format;
+ dsi->mode_flags = device->mode_flags;
++ dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
++ if (IS_ERR(dsi->next_bridge))
++ return PTR_ERR(dsi->next_bridge);
++
++ drm_bridge_add(&dsi->bridge);
++
++ ret = component_add(host->dev, &mtk_dsi_component_ops);
++ if (ret) {
++ DRM_ERROR("failed to add dsi_host component: %d\n", ret);
++ drm_bridge_remove(&dsi->bridge);
++ return ret;
++ }
+
+ return 0;
+ }
+
++static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
++ struct mipi_dsi_device *device)
++{
++ struct mtk_dsi *dsi = host_to_dsi(host);
++
++ component_del(host->dev, &mtk_dsi_component_ops);
++ drm_bridge_remove(&dsi->bridge);
++ return 0;
++}
++
+ static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
+ {
+ int ret;
+@@ -938,73 +1021,14 @@ static ssize_t mtk_dsi_host_transfer(str
+
+ static const struct mipi_dsi_host_ops mtk_dsi_ops = {
+ .attach = mtk_dsi_host_attach,
++ .detach = mtk_dsi_host_detach,
+ .transfer = mtk_dsi_host_transfer,
+ };
+
+-static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
+-{
+- int ret;
+-
+- ret = drm_simple_encoder_init(drm, &dsi->encoder,
+- DRM_MODE_ENCODER_DSI);
+- if (ret) {
+- DRM_ERROR("Failed to encoder init to drm\n");
+- return ret;
+- }
+-
+- dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev);
+-
+- ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
+- DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+- if (ret)
+- goto err_cleanup_encoder;
+-
+- dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder);
+- if (IS_ERR(dsi->connector)) {
+- DRM_ERROR("Unable to create bridge connector\n");
+- ret = PTR_ERR(dsi->connector);
+- goto err_cleanup_encoder;
+- }
+- drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
+-
+- return 0;
+-
+-err_cleanup_encoder:
+- drm_encoder_cleanup(&dsi->encoder);
+- return ret;
+-}
+-
+-static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
+-{
+- int ret;
+- struct drm_device *drm = data;
+- struct mtk_dsi *dsi = dev_get_drvdata(dev);
+-
+- ret = mtk_dsi_encoder_init(drm, dsi);
+- if (ret)
+- return ret;
+-
+- return device_reset_optional(dev);
+-}
+-
+-static void mtk_dsi_unbind(struct device *dev, struct device *master,
+- void *data)
+-{
+- struct mtk_dsi *dsi = dev_get_drvdata(dev);
+-
+- drm_encoder_cleanup(&dsi->encoder);
+-}
+-
+-static const struct component_ops mtk_dsi_component_ops = {
+- .bind = mtk_dsi_bind,
+- .unbind = mtk_dsi_unbind,
+-};
+-
+ static int mtk_dsi_probe(struct platform_device *pdev)
+ {
+ struct mtk_dsi *dsi;
+ struct device *dev = &pdev->dev;
+- struct drm_panel *panel;
+ struct resource *regs;
+ int irq_num;
+ int ret;
+@@ -1021,19 +1045,6 @@ static int mtk_dsi_probe(struct platform
+ return ret;
+ }
+
+- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
+- &panel, &dsi->next_bridge);
+- if (ret)
+- goto err_unregister_host;
+-
+- if (panel) {
+- dsi->next_bridge = devm_drm_panel_bridge_add(dev, panel);
+- if (IS_ERR(dsi->next_bridge)) {
+- ret = PTR_ERR(dsi->next_bridge);
+- goto err_unregister_host;
+- }
+- }
+-
+ dsi->driver_data = of_device_get_match_data(dev);
+
+ dsi->engine_clk = devm_clk_get(dev, "engine");
+@@ -1098,14 +1109,6 @@ static int mtk_dsi_probe(struct platform
+ dsi->bridge.of_node = dev->of_node;
+ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+
+- drm_bridge_add(&dsi->bridge);
+-
+- ret = component_add(&pdev->dev, &mtk_dsi_component_ops);
+- if (ret) {
+- dev_err(&pdev->dev, "failed to add component: %d\n", ret);
+- goto err_unregister_host;
+- }
+-
+ return 0;
+
+ err_unregister_host:
+@@ -1118,8 +1121,6 @@ static int mtk_dsi_remove(struct platfor
+ struct mtk_dsi *dsi = platform_get_drvdata(pdev);
+
+ mtk_output_dsi_disable(dsi);
+- drm_bridge_remove(&dsi->bridge);
+- component_del(&pdev->dev, &mtk_dsi_component_ops);
+ mipi_dsi_host_unregister(&dsi->host);
+
+ return 0;
--- /dev/null
+From 364438fd629f7611a84c8e6d7de91659300f1502 Mon Sep 17 00:00:00 2001
+From: Nicholas Bishop <nicholasbishop@google.com>
+Date: Fri, 11 Feb 2022 14:57:39 -0500
+Subject: drm/radeon: Fix backlight control on iMac 12,1
+
+From: Nicholas Bishop <nicholasbishop@google.com>
+
+commit 364438fd629f7611a84c8e6d7de91659300f1502 upstream.
+
+The iMac 12,1 does not use the gmux driver for backlight, so the radeon
+backlight device is needed to set the brightness.
+
+Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1838
+Signed-off-by: Nicholas Bishop <nicholasbishop@google.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/radeon/atombios_encoders.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/radeon/atombios_encoders.c
++++ b/drivers/gpu/drm/radeon/atombios_encoders.c
+@@ -198,7 +198,8 @@ void radeon_atom_backlight_init(struct r
+ * so don't register a backlight device
+ */
+ if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
+- (rdev->pdev->device == 0x6741))
++ (rdev->pdev->device == 0x6741) &&
++ !dmi_match(DMI_PRODUCT_NAME, "iMac12,1"))
+ return;
+
+ if (!radeon_encoder->enc_priv)
--- /dev/null
+From bea2662e7818e15d7607d17d57912ac984275d94 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 8 Feb 2022 11:47:30 +0100
+Subject: iwlwifi: fix use-after-free
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit bea2662e7818e15d7607d17d57912ac984275d94 upstream.
+
+If no firmware was present at all (or, presumably, all of the
+firmware files failed to parse), we end up unbinding by calling
+device_release_driver(), which calls remove(), which then in
+iwlwifi calls iwl_drv_stop(), freeing the 'drv' struct. However
+the new code I added will still erroneously access it after it
+was freed.
+
+Set 'failure=false' in this case to avoid the access, all data
+was already freed anyway.
+
+Cc: stable@vger.kernel.org
+Reported-by: Stefan Agner <stefan@agner.ch>
+Reported-by: Wolfgang Walter <linux@stwm.de>
+Reported-by: Jason Self <jason@bluehome.net>
+Reported-by: Dominik Behr <dominik@dominikbehr.com>
+Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
+Fixes: ab07506b0454 ("iwlwifi: fix leaks/bad data after failed firmware load")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/20220208114728.e6b514cf4c85.Iffb575ca2a623d7859b542c33b2a507d01554251@changeid
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+@@ -1656,6 +1656,8 @@ static void iwl_req_fw_callback(const st
+ out_unbind:
+ complete(&drv->request_firmware_complete);
+ device_release_driver(drv->trans->dev);
++ /* drv has just been freed by the release */
++ failure = false;
+ free:
+ if (failure)
+ iwl_dealloc_ucode(drv);
--- /dev/null
+From 92883a524ae918736a7b8acef98698075507b8c1 Mon Sep 17 00:00:00 2001
+From: Luca Coelho <luciano.coelho@intel.com>
+Date: Fri, 28 Jan 2022 14:48:50 +0200
+Subject: iwlwifi: remove deprecated broadcast filtering feature
+
+From: Luca Coelho <luciano.coelho@intel.com>
+
+commit 92883a524ae918736a7b8acef98698075507b8c1 upstream.
+
+This feature has been deprecated and should not be used anymore. With
+newer firmwares, namely *-67.ucode and above, trying to use it causes an
+assertion failure in the FW, similar to this:
+
+[Tue Jan 11 20:05:24 2022] iwlwifi 0000:04:00.0: 0x00001062 | ADVANCED_SYSASSERT
+
+In order to prevent this feature from being used, remove it entirely
+and get rid of the Kconfig option that
+enables it (IWLWIFI_BCAST_FILTERING).
+
+Fixes: cbaa6aeedee5 ("iwlwifi: bump FW API to 67 for AX devices")
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=215488
+Cc: stable@vger.kernel.org # 5.16.x
+Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/iwlwifi.20220128144623.9241e049f13e.Ia4f282813ca2ddd24c13427823519113f2bbebf2@changeid
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/intel/iwlwifi/Kconfig | 13 -
+ drivers/net/wireless/intel/iwlwifi/fw/api/commands.h | 5
+ drivers/net/wireless/intel/iwlwifi/fw/api/filter.h | 88 ------
+ drivers/net/wireless/intel/iwlwifi/fw/file.h | 2
+ drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 203 ----------------
+ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 240 -------------------
+ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 13 -
+ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1
+ 8 files changed, 565 deletions(-)
+
+--- a/drivers/net/wireless/intel/iwlwifi/Kconfig
++++ b/drivers/net/wireless/intel/iwlwifi/Kconfig
+@@ -79,19 +79,6 @@ config IWLWIFI_OPMODE_MODULAR
+ comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
+ depends on IWLDVM=n && IWLMVM=n
+
+-config IWLWIFI_BCAST_FILTERING
+- bool "Enable broadcast filtering"
+- depends on IWLMVM
+- help
+- Say Y here to enable default bcast filtering configuration.
+-
+- Enabling broadcast filtering will drop any incoming wireless
+- broadcast frames, except some very specific predefined
+- patterns (e.g. incoming arp requests).
+-
+- If unsure, don't enable this option, as some programs might
+- expect incoming broadcasts for their normal operations.
+-
+ menu "Debugging Options"
+
+ config IWLWIFI_DEBUG
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+@@ -506,11 +506,6 @@ enum iwl_legacy_cmds {
+ DEBUG_LOG_MSG = 0xf7,
+
+ /**
+- * @BCAST_FILTER_CMD: &struct iwl_bcast_filter_cmd
+- */
+- BCAST_FILTER_CMD = 0xcf,
+-
+- /**
+ * @MCAST_FILTER_CMD: &struct iwl_mcast_filter_cmd
+ */
+ MCAST_FILTER_CMD = 0xd0,
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/filter.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/filter.h
+@@ -36,92 +36,4 @@ struct iwl_mcast_filter_cmd {
+ u8 addr_list[0];
+ } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
+
+-#define MAX_BCAST_FILTERS 8
+-#define MAX_BCAST_FILTER_ATTRS 2
+-
+-/**
+- * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet
+- * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start.
+- * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e.
+- * start of ip payload).
+- */
+-enum iwl_mvm_bcast_filter_attr_offset {
+- BCAST_FILTER_OFFSET_PAYLOAD_START = 0,
+- BCAST_FILTER_OFFSET_IP_END = 1,
+-};
+-
+-/**
+- * struct iwl_fw_bcast_filter_attr - broadcast filter attribute
+- * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset.
+- * @offset: starting offset of this pattern.
+- * @reserved1: reserved
+- * @val: value to match - big endian (MSB is the first
+- * byte to match from offset pos).
+- * @mask: mask to match (big endian).
+- */
+-struct iwl_fw_bcast_filter_attr {
+- u8 offset_type;
+- u8 offset;
+- __le16 reserved1;
+- __be32 val;
+- __be32 mask;
+-} __packed; /* BCAST_FILTER_ATT_S_VER_1 */
+-
+-/**
+- * enum iwl_mvm_bcast_filter_frame_type - filter frame type
+- * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames.
+- * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames
+- */
+-enum iwl_mvm_bcast_filter_frame_type {
+- BCAST_FILTER_FRAME_TYPE_ALL = 0,
+- BCAST_FILTER_FRAME_TYPE_IPV4 = 1,
+-};
+-
+-/**
+- * struct iwl_fw_bcast_filter - broadcast filter
+- * @discard: discard frame (1) or let it pass (0).
+- * @frame_type: &enum iwl_mvm_bcast_filter_frame_type.
+- * @reserved1: reserved
+- * @num_attrs: number of valid attributes in this filter.
+- * @attrs: attributes of this filter. a filter is considered matched
+- * only when all its attributes are matched (i.e. AND relationship)
+- */
+-struct iwl_fw_bcast_filter {
+- u8 discard;
+- u8 frame_type;
+- u8 num_attrs;
+- u8 reserved1;
+- struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS];
+-} __packed; /* BCAST_FILTER_S_VER_1 */
+-
+-/**
+- * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration.
+- * @default_discard: default action for this mac (discard (1) / pass (0)).
+- * @reserved1: reserved
+- * @attached_filters: bitmap of relevant filters for this mac.
+- */
+-struct iwl_fw_bcast_mac {
+- u8 default_discard;
+- u8 reserved1;
+- __le16 attached_filters;
+-} __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */
+-
+-/**
+- * struct iwl_bcast_filter_cmd - broadcast filtering configuration
+- * @disable: enable (0) / disable (1)
+- * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS)
+- * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER)
+- * @reserved1: reserved
+- * @filters: broadcast filters
+- * @macs: broadcast filtering configuration per-mac
+- */
+-struct iwl_bcast_filter_cmd {
+- u8 disable;
+- u8 max_bcast_filters;
+- u8 max_macs;
+- u8 reserved1;
+- struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS];
+- struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER];
+-} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */
+-
+ #endif /* __iwl_fw_api_filter_h__ */
+--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
+@@ -182,7 +182,6 @@ struct iwl_ucode_capa {
+ * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
+ * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD
+ * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
+- * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
+ * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS.
+ */
+ enum iwl_ucode_tlv_flag {
+@@ -197,7 +196,6 @@ enum iwl_ucode_tlv_flag {
+ IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
+ IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25),
+ IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26),
+- IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29),
+ };
+
+ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+@@ -1361,189 +1361,6 @@ static ssize_t iwl_dbgfs_dbg_time_point_
+ return count;
+ }
+
+-#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
+-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+-static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
+- char __user *user_buf,
+- size_t count, loff_t *ppos)
+-{
+- struct iwl_mvm *mvm = file->private_data;
+- struct iwl_bcast_filter_cmd cmd;
+- const struct iwl_fw_bcast_filter *filter;
+- char *buf;
+- int bufsz = 1024;
+- int i, j, pos = 0;
+- ssize_t ret;
+-
+- buf = kzalloc(bufsz, GFP_KERNEL);
+- if (!buf)
+- return -ENOMEM;
+-
+- mutex_lock(&mvm->mutex);
+- if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
+- ADD_TEXT("None\n");
+- mutex_unlock(&mvm->mutex);
+- goto out;
+- }
+- mutex_unlock(&mvm->mutex);
+-
+- for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
+- filter = &cmd.filters[i];
+-
+- ADD_TEXT("Filter [%d]:\n", i);
+- ADD_TEXT("\tDiscard=%d\n", filter->discard);
+- ADD_TEXT("\tFrame Type: %s\n",
+- filter->frame_type ? "IPv4" : "Generic");
+-
+- for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
+- const struct iwl_fw_bcast_filter_attr *attr;
+-
+- attr = &filter->attrs[j];
+- if (!attr->mask)
+- break;
+-
+- ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
+- j, attr->offset,
+- attr->offset_type ? "IP End" :
+- "Payload Start",
+- be32_to_cpu(attr->mask),
+- be32_to_cpu(attr->val),
+- le16_to_cpu(attr->reserved1));
+- }
+- }
+-out:
+- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+- kfree(buf);
+- return ret;
+-}
+-
+-static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
+- size_t count, loff_t *ppos)
+-{
+- int pos, next_pos;
+- struct iwl_fw_bcast_filter filter = {};
+- struct iwl_bcast_filter_cmd cmd;
+- u32 filter_id, attr_id, mask, value;
+- int err = 0;
+-
+- if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
+- &filter.frame_type, &pos) != 3)
+- return -EINVAL;
+-
+- if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
+- filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
+- return -EINVAL;
+-
+- for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
+- attr_id++) {
+- struct iwl_fw_bcast_filter_attr *attr =
+- &filter.attrs[attr_id];
+-
+- if (pos >= count)
+- break;
+-
+- if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
+- &attr->offset, &attr->offset_type,
+- &mask, &value, &next_pos) != 4)
+- return -EINVAL;
+-
+- attr->mask = cpu_to_be32(mask);
+- attr->val = cpu_to_be32(value);
+- if (mask)
+- filter.num_attrs++;
+-
+- pos += next_pos;
+- }
+-
+- mutex_lock(&mvm->mutex);
+- memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
+- &filter, sizeof(filter));
+-
+- /* send updated bcast filtering configuration */
+- if (iwl_mvm_firmware_running(mvm) &&
+- mvm->dbgfs_bcast_filtering.override &&
+- iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
+- err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
+- sizeof(cmd), &cmd);
+- mutex_unlock(&mvm->mutex);
+-
+- return err ?: count;
+-}
+-
+-static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
+- char __user *user_buf,
+- size_t count, loff_t *ppos)
+-{
+- struct iwl_mvm *mvm = file->private_data;
+- struct iwl_bcast_filter_cmd cmd;
+- char *buf;
+- int bufsz = 1024;
+- int i, pos = 0;
+- ssize_t ret;
+-
+- buf = kzalloc(bufsz, GFP_KERNEL);
+- if (!buf)
+- return -ENOMEM;
+-
+- mutex_lock(&mvm->mutex);
+- if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
+- ADD_TEXT("None\n");
+- mutex_unlock(&mvm->mutex);
+- goto out;
+- }
+- mutex_unlock(&mvm->mutex);
+-
+- for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
+- const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
+-
+- ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
+- i, mac->default_discard, mac->attached_filters);
+- }
+-out:
+- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+- kfree(buf);
+- return ret;
+-}
+-
+-static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
+- char *buf, size_t count,
+- loff_t *ppos)
+-{
+- struct iwl_bcast_filter_cmd cmd;
+- struct iwl_fw_bcast_mac mac = {};
+- u32 mac_id, attached_filters;
+- int err = 0;
+-
+- if (!mvm->bcast_filters)
+- return -ENOENT;
+-
+- if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
+- &attached_filters) != 3)
+- return -EINVAL;
+-
+- if (mac_id >= ARRAY_SIZE(cmd.macs) ||
+- mac.default_discard > 1 ||
+- attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
+- return -EINVAL;
+-
+- mac.attached_filters = cpu_to_le16(attached_filters);
+-
+- mutex_lock(&mvm->mutex);
+- memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
+- &mac, sizeof(mac));
+-
+- /* send updated bcast filtering configuration */
+- if (iwl_mvm_firmware_running(mvm) &&
+- mvm->dbgfs_bcast_filtering.override &&
+- iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
+- err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
+- sizeof(cmd), &cmd);
+- mutex_unlock(&mvm->mutex);
+-
+- return err ?: count;
+-}
+-#endif
+-
+ #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
+ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
+ #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
+@@ -1873,11 +1690,6 @@ MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon
+
+ MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids);
+
+-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+-MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
+-MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
+-#endif
+-
+ #ifdef CONFIG_ACPI
+ MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
+ #endif
+@@ -2088,21 +1900,6 @@ void iwl_mvm_dbgfs_register(struct iwl_m
+
+ MVM_DEBUGFS_ADD_FILE(uapsd_noagg_bssids, mvm->debugfs_dir, S_IRUSR);
+
+-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
+- bcast_dir = debugfs_create_dir("bcast_filtering",
+- mvm->debugfs_dir);
+-
+- debugfs_create_bool("override", 0600, bcast_dir,
+- &mvm->dbgfs_bcast_filtering.override);
+-
+- MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
+- bcast_dir, 0600);
+- MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
+- bcast_dir, 0600);
+- }
+-#endif
+-
+ #ifdef CONFIG_PM_SLEEP
+ MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400);
+ debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir,
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+@@ -55,79 +55,6 @@ static const struct ieee80211_iface_comb
+ },
+ };
+
+-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+-/*
+- * Use the reserved field to indicate magic values.
+- * these values will only be used internally by the driver,
+- * and won't make it to the fw (reserved will be 0).
+- * BC_FILTER_MAGIC_IP - configure the val of this attribute to
+- * be the vif's ip address. in case there is not a single
+- * ip address (0, or more than 1), this attribute will
+- * be skipped.
+- * BC_FILTER_MAGIC_MAC - set the val of this attribute to
+- * the LSB bytes of the vif's mac address
+- */
+-enum {
+- BC_FILTER_MAGIC_NONE = 0,
+- BC_FILTER_MAGIC_IP,
+- BC_FILTER_MAGIC_MAC,
+-};
+-
+-static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = {
+- {
+- /* arp */
+- .discard = 0,
+- .frame_type = BCAST_FILTER_FRAME_TYPE_ALL,
+- .attrs = {
+- {
+- /* frame type - arp, hw type - ethernet */
+- .offset_type =
+- BCAST_FILTER_OFFSET_PAYLOAD_START,
+- .offset = sizeof(rfc1042_header),
+- .val = cpu_to_be32(0x08060001),
+- .mask = cpu_to_be32(0xffffffff),
+- },
+- {
+- /* arp dest ip */
+- .offset_type =
+- BCAST_FILTER_OFFSET_PAYLOAD_START,
+- .offset = sizeof(rfc1042_header) + 2 +
+- sizeof(struct arphdr) +
+- ETH_ALEN + sizeof(__be32) +
+- ETH_ALEN,
+- .mask = cpu_to_be32(0xffffffff),
+- /* mark it as special field */
+- .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP),
+- },
+- },
+- },
+- {
+- /* dhcp offer bcast */
+- .discard = 0,
+- .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4,
+- .attrs = {
+- {
+- /* udp dest port - 68 (bootp client)*/
+- .offset_type = BCAST_FILTER_OFFSET_IP_END,
+- .offset = offsetof(struct udphdr, dest),
+- .val = cpu_to_be32(0x00440000),
+- .mask = cpu_to_be32(0xffff0000),
+- },
+- {
+- /* dhcp - lsb bytes of client hw address */
+- .offset_type = BCAST_FILTER_OFFSET_IP_END,
+- .offset = 38,
+- .mask = cpu_to_be32(0xffffffff),
+- /* mark it as special field */
+- .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC),
+- },
+- },
+- },
+- /* last filter must be empty */
+- {},
+-};
+-#endif
+-
+ static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
+ .max_peers = IWL_MVM_TOF_MAX_APS,
+ .report_ap_tsf = 1,
+@@ -683,11 +610,6 @@ int iwl_mvm_mac_setup_register(struct iw
+ }
+ #endif
+
+-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+- /* assign default bcast filtering configuration */
+- mvm->bcast_filters = iwl_mvm_default_bcast_filters;
+-#endif
+-
+ ret = iwl_mvm_leds_init(mvm);
+ if (ret)
+ return ret;
+@@ -1803,162 +1725,6 @@ static void iwl_mvm_config_iface_filter(
+ mutex_unlock(&mvm->mutex);
+ }
+
+-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+-struct iwl_bcast_iter_data {
+- struct iwl_mvm *mvm;
+- struct iwl_bcast_filter_cmd *cmd;
+- u8 current_filter;
+-};
+-
+-static void
+-iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif,
+- const struct iwl_fw_bcast_filter *in_filter,
+- struct iwl_fw_bcast_filter *out_filter)
+-{
+- struct iwl_fw_bcast_filter_attr *attr;
+- int i;
+-
+- memcpy(out_filter, in_filter, sizeof(*out_filter));
+-
+- for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) {
+- attr = &out_filter->attrs[i];
+-
+- if (!attr->mask)
+- break;
+-
+- switch (attr->reserved1) {
+- case cpu_to_le16(BC_FILTER_MAGIC_IP):
+- if (vif->bss_conf.arp_addr_cnt != 1) {
+- attr->mask = 0;
+- continue;
+- }
+-
+- attr->val = vif->bss_conf.arp_addr_list[0];
+- break;
+- case cpu_to_le16(BC_FILTER_MAGIC_MAC):
+- attr->val = *(__be32 *)&vif->addr[2];
+- break;
+- default:
+- break;
+- }
+- attr->reserved1 = 0;
+- out_filter->num_attrs++;
+- }
+-}
+-
+-static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac,
+- struct ieee80211_vif *vif)
+-{
+- struct iwl_bcast_iter_data *data = _data;
+- struct iwl_mvm *mvm = data->mvm;
+- struct iwl_bcast_filter_cmd *cmd = data->cmd;
+- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+- struct iwl_fw_bcast_mac *bcast_mac;
+- int i;
+-
+- if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs)))
+- return;
+-
+- bcast_mac = &cmd->macs[mvmvif->id];
+-
+- /*
+- * enable filtering only for associated stations, but not for P2P
+- * Clients
+- */
+- if (vif->type != NL80211_IFTYPE_STATION || vif->p2p ||
+- !vif->bss_conf.assoc)
+- return;
+-
+- bcast_mac->default_discard = 1;
+-
+- /* copy all configured filters */
+- for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) {
+- /*
+- * Make sure we don't exceed our filters limit.
+- * if there is still a valid filter to be configured,
+- * be on the safe side and just allow bcast for this mac.
+- */
+- if (WARN_ON_ONCE(data->current_filter >=
+- ARRAY_SIZE(cmd->filters))) {
+- bcast_mac->default_discard = 0;
+- bcast_mac->attached_filters = 0;
+- break;
+- }
+-
+- iwl_mvm_set_bcast_filter(vif,
+- &mvm->bcast_filters[i],
+- &cmd->filters[data->current_filter]);
+-
+- /* skip current filter if it contains no attributes */
+- if (!cmd->filters[data->current_filter].num_attrs)
+- continue;
+-
+- /* attach the filter to current mac */
+- bcast_mac->attached_filters |=
+- cpu_to_le16(BIT(data->current_filter));
+-
+- data->current_filter++;
+- }
+-}
+-
+-bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
+- struct iwl_bcast_filter_cmd *cmd)
+-{
+- struct iwl_bcast_iter_data iter_data = {
+- .mvm = mvm,
+- .cmd = cmd,
+- };
+-
+- if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
+- return false;
+-
+- memset(cmd, 0, sizeof(*cmd));
+- cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
+- cmd->max_macs = ARRAY_SIZE(cmd->macs);
+-
+-#ifdef CONFIG_IWLWIFI_DEBUGFS
+- /* use debugfs filters/macs if override is configured */
+- if (mvm->dbgfs_bcast_filtering.override) {
+- memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters,
+- sizeof(cmd->filters));
+- memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs,
+- sizeof(cmd->macs));
+- return true;
+- }
+-#endif
+-
+- /* if no filters are configured, do nothing */
+- if (!mvm->bcast_filters)
+- return false;
+-
+- /* configure and attach these filters for each associated sta vif */
+- ieee80211_iterate_active_interfaces(
+- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+- iwl_mvm_bcast_filter_iterator, &iter_data);
+-
+- return true;
+-}
+-
+-static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
+-{
+- struct iwl_bcast_filter_cmd cmd;
+-
+- if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING))
+- return 0;
+-
+- if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
+- return 0;
+-
+- return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
+- sizeof(cmd), &cmd);
+-}
+-#else
+-static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
+-{
+- return 0;
+-}
+-#endif
+-
+ static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+ {
+@@ -2469,7 +2235,6 @@ static void iwl_mvm_bss_info_changed_sta
+ }
+
+ iwl_mvm_recalc_multicast(mvm);
+- iwl_mvm_configure_bcast_filter(mvm);
+
+ /* reset rssi values */
+ mvmvif->bf_data.ave_beacon_signal = 0;
+@@ -2519,11 +2284,6 @@ static void iwl_mvm_bss_info_changed_sta
+ }
+ }
+
+- if (changes & BSS_CHANGED_ARP_FILTER) {
+- IWL_DEBUG_MAC80211(mvm, "arp filter changed\n");
+- iwl_mvm_configure_bcast_filter(mvm);
+- }
+-
+ if (changes & BSS_CHANGED_BANDWIDTH)
+ iwl_mvm_apply_fw_smps_request(vif);
+ }
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+@@ -872,17 +872,6 @@ struct iwl_mvm {
+ /* rx chain antennas set through debugfs for the scan command */
+ u8 scan_rx_ant;
+
+-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
+- /* broadcast filters to configure for each associated station */
+- const struct iwl_fw_bcast_filter *bcast_filters;
+-#ifdef CONFIG_IWLWIFI_DEBUGFS
+- struct {
+- bool override;
+- struct iwl_bcast_filter_cmd cmd;
+- } dbgfs_bcast_filtering;
+-#endif
+-#endif
+-
+ /* Internal station */
+ struct iwl_mvm_int_sta aux_sta;
+ struct iwl_mvm_int_sta snif_sta;
+@@ -1570,8 +1559,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm);
+ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
+
+ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm);
+-bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
+- struct iwl_bcast_filter_cmd *cmd);
+
+ /*
+ * FW notifications / CMD responses handlers
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+@@ -474,7 +474,6 @@ static const struct iwl_hcmd_names iwl_m
+ HCMD_NAME(MCC_CHUB_UPDATE_CMD),
+ HCMD_NAME(MARKER_CMD),
+ HCMD_NAME(BT_PROFILE_NOTIFICATION),
+- HCMD_NAME(BCAST_FILTER_CMD),
+ HCMD_NAME(MCAST_FILTER_CMD),
+ HCMD_NAME(REPLY_SF_CFG_CMD),
+ HCMD_NAME(REPLY_BEACON_FILTERING_CMD),
--- /dev/null
+From e1779c2714c3023e4629825762bcbc43a3b943df Mon Sep 17 00:00:00 2001
+From: Maxim Levitsky <mlevitsk@redhat.com>
+Date: Mon, 7 Feb 2022 17:54:19 +0200
+Subject: KVM: x86: nSVM: fix potential NULL derefernce on nested migration
+
+From: Maxim Levitsky <mlevitsk@redhat.com>
+
+commit e1779c2714c3023e4629825762bcbc43a3b943df upstream.
+
+Turns out that due to review feedback and/or rebases
+I accidentally moved the call to nested_svm_load_cr3 to be too early,
+before the NPT is enabled, which is very wrong to do.
+
+KVM can't even access guest memory at that point as nested NPT
+is needed for that, and of course it won't initialize the walk_mmu,
+which is main issue the patch was addressing.
+
+Fix this for real.
+
+Fixes: 232f75d3b4b5 ("KVM: nSVM: call nested_svm_load_cr3 on nested state load")
+Cc: stable@vger.kernel.org
+
+Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
+Message-Id: <20220207155447.840194-3-mlevitsk@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/nested.c | 26 ++++++++++++++------------
+ 1 file changed, 14 insertions(+), 12 deletions(-)
+
+--- a/arch/x86/kvm/svm/nested.c
++++ b/arch/x86/kvm/svm/nested.c
+@@ -1389,18 +1389,6 @@ static int svm_set_nested_state(struct k
+ !nested_vmcb_valid_sregs(vcpu, save))
+ goto out_free;
+
+- /*
+- * While the nested guest CR3 is already checked and set by
+- * KVM_SET_SREGS, it was set when nested state was yet loaded,
+- * thus MMU might not be initialized correctly.
+- * Set it again to fix this.
+- */
+-
+- ret = nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
+- nested_npt_enabled(svm), false);
+- if (WARN_ON_ONCE(ret))
+- goto out_free;
+-
+
+ /*
+ * All checks done, we can enter guest mode. Userspace provides
+@@ -1426,6 +1414,20 @@ static int svm_set_nested_state(struct k
+
+ svm_switch_vmcb(svm, &svm->nested.vmcb02);
+ nested_vmcb02_prepare_control(svm);
++
++ /*
++ * While the nested guest CR3 is already checked and set by
++ * KVM_SET_SREGS, it was set when nested state was yet loaded,
++ * thus MMU might not be initialized correctly.
++ * Set it again to fix this.
++ */
++
++ ret = nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
++ nested_npt_enabled(svm), false);
++ if (WARN_ON_ONCE(ret))
++ goto out_free;
++
++
+ kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
+ ret = 0;
+ out_free:
--- /dev/null
+From e8efa4ff00374d2e6f47f6e4628ca3b541c001af Mon Sep 17 00:00:00 2001
+From: Maxim Levitsky <mlevitsk@redhat.com>
+Date: Mon, 7 Feb 2022 17:54:20 +0200
+Subject: KVM: x86: nSVM: mark vmcb01 as dirty when restoring SMM saved state
+
+From: Maxim Levitsky <mlevitsk@redhat.com>
+
+commit e8efa4ff00374d2e6f47f6e4628ca3b541c001af upstream.
+
+While usually, restoring the smm state makes the KVM enter
+the nested guest thus a different vmcb (vmcb02 vs vmcb01),
+KVM should still mark it as dirty, since hardware
+can in theory cache multiple vmcbs.
+
+Failure to do so, combined with lack of setting the
+nested_run_pending (which is fixed in the next patch),
+might make KVM re-enter vmcb01, which was just exited from,
+with completely different set of guest state registers
+(SMM vs non SMM) and without proper dirty bits set,
+which results in the CPU reusing stale IDTR pointer
+which leads to a guest shutdown on any interrupt.
+
+On the real hardware this usually doesn't happen,
+but when running nested, L0's KVM does check and
+honour few dirty bits, causing this issue to happen.
+
+This patch fixes boot of hyperv and SMM enabled
+windows VM running nested on KVM.
+
+Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
+Cc: stable@vger.kernel.org
+Message-Id: <20220207155447.840194-4-mlevitsk@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/svm.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -4449,6 +4449,8 @@ static int svm_leave_smm(struct kvm_vcpu
+ * Enter the nested guest now
+ */
+
++ vmcb_mark_all_dirty(svm->vmcb01.ptr);
++
+ vmcb12 = map.hva;
+ nested_load_control_from_vmcb12(svm, &vmcb12->control);
+ ret = enter_svm_guest_mode(vcpu, vmcb12_gpa, vmcb12, false);
--- /dev/null
+From 759cbd59674a6c0aec616a3f4f0740ebd3f5fbef Mon Sep 17 00:00:00 2001
+From: Maxim Levitsky <mlevitsk@redhat.com>
+Date: Mon, 7 Feb 2022 17:54:21 +0200
+Subject: KVM: x86: nSVM/nVMX: set nested_run_pending on VM entry which is a result of RSM
+
+From: Maxim Levitsky <mlevitsk@redhat.com>
+
+commit 759cbd59674a6c0aec616a3f4f0740ebd3f5fbef upstream.
+
+While RSM induced VM entries are not full VM entries,
+they still need to be followed by actual VM entry to complete it,
+unlike setting the nested state.
+
+This patch fixes boot of hyperv and SMM enabled
+windows VM running nested on KVM, which fail due
+to this issue combined with lack of dirty bit setting.
+
+Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
+Cc: stable@vger.kernel.org
+Message-Id: <20220207155447.840194-5-mlevitsk@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/svm.c | 5 +++++
+ arch/x86/kvm/vmx/vmx.c | 1 +
+ 2 files changed, 6 insertions(+)
+
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -4445,6 +4445,11 @@ static int svm_leave_smm(struct kvm_vcpu
+ nested_load_control_from_vmcb12(svm, &vmcb12->control);
+ ret = enter_svm_guest_mode(vcpu, vmcb12_gpa, vmcb12, false);
+
++ if (ret)
++ goto unmap_save;
++
++ svm->nested.nested_run_pending = 1;
++
+ unmap_save:
+ kvm_vcpu_unmap(vcpu, &map_save, true);
+ unmap_map:
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -7534,6 +7534,7 @@ static int vmx_leave_smm(struct kvm_vcpu
+ if (ret)
+ return ret;
+
++ vmx->nested.nested_run_pending = 1;
+ vmx->nested.smm.guest_mode = false;
+ }
+ return 0;
--- /dev/null
+From c53bbe2145f51d3bc0438c2db02e737b9b598bf3 Mon Sep 17 00:00:00 2001
+From: Maxim Levitsky <mlevitsk@redhat.com>
+Date: Mon, 7 Feb 2022 17:54:18 +0200
+Subject: KVM: x86: SVM: don't passthrough SMAP/SMEP/PKE bits in !NPT && !gCR0.PG case
+
+From: Maxim Levitsky <mlevitsk@redhat.com>
+
+commit c53bbe2145f51d3bc0438c2db02e737b9b598bf3 upstream.
+
+When the guest doesn't enable paging, and NPT/EPT is disabled, we
+use guest't paging CR3's as KVM's shadow paging pointer and
+we are technically in direct mode as if we were to use NPT/EPT.
+
+In direct mode we create SPTEs with user mode permissions
+because usually in the direct mode the NPT/EPT doesn't
+need to restrict access based on guest CPL
+(there are MBE/GMET extenstions for that but KVM doesn't use them).
+
+In this special "use guest paging as direct" mode however,
+and if CR4.SMAP/CR4.SMEP are enabled, that will make the CPU
+fault on each access and KVM will enter endless loop of page faults.
+
+Since page protection doesn't have any meaning in !PG case,
+just don't passthrough these bits.
+
+The fix is the same as was done for VMX in commit:
+commit 656ec4a4928a ("KVM: VMX: fix SMEP and SMAP without EPT")
+
+This fixes the boot of windows 10 without NPT for good.
+(Without this patch, BSP boots, but APs were stuck in endless
+loop of page faults, causing the VM boot with 1 CPU)
+
+Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
+Cc: stable@vger.kernel.org
+Message-Id: <20220207155447.840194-2-mlevitsk@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/svm.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -1795,6 +1795,7 @@ void svm_set_cr0(struct kvm_vcpu *vcpu,
+ {
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 hcr0 = cr0;
++ bool old_paging = is_paging(vcpu);
+
+ #ifdef CONFIG_X86_64
+ if (vcpu->arch.efer & EFER_LME && !vcpu->arch.guest_state_protected) {
+@@ -1811,8 +1812,11 @@ void svm_set_cr0(struct kvm_vcpu *vcpu,
+ #endif
+ vcpu->arch.cr0 = cr0;
+
+- if (!npt_enabled)
++ if (!npt_enabled) {
+ hcr0 |= X86_CR0_PG | X86_CR0_WP;
++ if (old_paging != is_paging(vcpu))
++ svm_set_cr4(vcpu, kvm_read_cr4(vcpu));
++ }
+
+ /*
+ * re-enable caching here because the QEMU bios
+@@ -1856,8 +1860,12 @@ void svm_set_cr4(struct kvm_vcpu *vcpu,
+ svm_flush_tlb(vcpu);
+
+ vcpu->arch.cr4 = cr4;
+- if (!npt_enabled)
++ if (!npt_enabled) {
+ cr4 |= X86_CR4_PAE;
++
++ if (!is_paging(vcpu))
++ cr4 &= ~(X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE);
++ }
+ cr4 |= host_cr4_mce;
+ to_svm(vcpu)->vmcb->save.cr4 = cr4;
+ vmcb_mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR);
--- /dev/null
+From fcb732d8f8cf6084f8480015ad41d25fb023a4dd Mon Sep 17 00:00:00 2001
+From: David Woodhouse <dwmw@amazon.co.uk>
+Date: Mon, 25 Oct 2021 14:29:01 +0100
+Subject: KVM: x86/xen: Fix runstate updates to be atomic when preempting vCPU
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: David Woodhouse <dwmw@amazon.co.uk>
+
+commit fcb732d8f8cf6084f8480015ad41d25fb023a4dd upstream.
+
+There are circumstances whem kvm_xen_update_runstate_guest() should not
+sleep because it ends up being called from __schedule() when the vCPU
+is preempted:
+
+[ 222.830825] kvm_xen_update_runstate_guest+0x24/0x100
+[ 222.830878] kvm_arch_vcpu_put+0x14c/0x200
+[ 222.830920] kvm_sched_out+0x30/0x40
+[ 222.830960] __schedule+0x55c/0x9f0
+
+To handle this, make it use the same trick as __kvm_xen_has_interrupt(),
+of using the hva from the gfn_to_hva_cache directly. Then it can use
+pagefault_disable() around the accesses and just bail out if the page
+is absent (which is unlikely).
+
+I almost switched to using a gfn_to_pfn_cache here and bailing out if
+kvm_map_gfn() fails, like kvm_steal_time_set_preempted() does — but on
+closer inspection it looks like kvm_map_gfn() will *always* fail in
+atomic context for a page in IOMEM, which means it will silently fail
+to make the update every single time for such guests, AFAICT. So I
+didn't do it that way after all. And will probably fix that one too.
+
+Cc: stable@vger.kernel.org
+Fixes: 30b5c851af79 ("KVM: x86/xen: Add support for vCPU runstate information")
+Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
+Message-Id: <b17a93e5ff4561e57b1238e3e7ccd0b613eb827e.camel@infradead.org>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/xen.c | 97 ++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 67 insertions(+), 30 deletions(-)
+
+--- a/arch/x86/kvm/xen.c
++++ b/arch/x86/kvm/xen.c
+@@ -93,32 +93,57 @@ static void kvm_xen_update_runstate(stru
+ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
+ {
+ struct kvm_vcpu_xen *vx = &v->arch.xen;
++ struct gfn_to_hva_cache *ghc = &vx->runstate_cache;
++ struct kvm_memslots *slots = kvm_memslots(v->kvm);
++ bool atomic = (state == RUNSTATE_runnable);
+ uint64_t state_entry_time;
+- unsigned int offset;
++ int __user *user_state;
++ uint64_t __user *user_times;
+
+ kvm_xen_update_runstate(v, state);
+
+ if (!vx->runstate_set)
+ return;
+
+- BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c);
++ if (unlikely(slots->generation != ghc->generation || kvm_is_error_hva(ghc->hva)) &&
++ kvm_gfn_to_hva_cache_init(v->kvm, ghc, ghc->gpa, ghc->len))
++ return;
++
++ /* We made sure it fits in a single page */
++ BUG_ON(!ghc->memslot);
++
++ if (atomic)
++ pagefault_disable();
+
+- offset = offsetof(struct compat_vcpu_runstate_info, state_entry_time);
+-#ifdef CONFIG_X86_64
+ /*
+- * The only difference is alignment of uint64_t in 32-bit.
+- * So the first field 'state' is accessed directly using
+- * offsetof() (where its offset happens to be zero), while the
+- * remaining fields which are all uint64_t, start at 'offset'
+- * which we tweak here by adding 4.
++ * The only difference between 32-bit and 64-bit versions of the
++ * runstate struct us the alignment of uint64_t in 32-bit, which
++ * means that the 64-bit version has an additional 4 bytes of
++ * padding after the first field 'state'.
++ *
++ * So we use 'int __user *user_state' to point to the state field,
++ * and 'uint64_t __user *user_times' for runstate_entry_time. So
++ * the actual array of time[] in each state starts at user_times[1].
+ */
++ BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) != 0);
++ BUILD_BUG_ON(offsetof(struct compat_vcpu_runstate_info, state) != 0);
++ user_state = (int __user *)ghc->hva;
++
++ BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c);
++
++ user_times = (uint64_t __user *)(ghc->hva +
++ offsetof(struct compat_vcpu_runstate_info,
++ state_entry_time));
++#ifdef CONFIG_X86_64
+ BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state_entry_time) !=
+ offsetof(struct compat_vcpu_runstate_info, state_entry_time) + 4);
+ BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, time) !=
+ offsetof(struct compat_vcpu_runstate_info, time) + 4);
+
+ if (v->kvm->arch.xen.long_mode)
+- offset = offsetof(struct vcpu_runstate_info, state_entry_time);
++ user_times = (uint64_t __user *)(ghc->hva +
++ offsetof(struct vcpu_runstate_info,
++ state_entry_time));
+ #endif
+ /*
+ * First write the updated state_entry_time at the appropriate
+@@ -132,10 +157,8 @@ void kvm_xen_update_runstate_guest(struc
+ BUILD_BUG_ON(sizeof_field(struct compat_vcpu_runstate_info, state_entry_time) !=
+ sizeof(state_entry_time));
+
+- if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
+- &state_entry_time, offset,
+- sizeof(state_entry_time)))
+- return;
++ if (__put_user(state_entry_time, user_times))
++ goto out;
+ smp_wmb();
+
+ /*
+@@ -149,11 +172,8 @@ void kvm_xen_update_runstate_guest(struc
+ BUILD_BUG_ON(sizeof_field(struct compat_vcpu_runstate_info, state) !=
+ sizeof(vx->current_runstate));
+
+- if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
+- &vx->current_runstate,
+- offsetof(struct vcpu_runstate_info, state),
+- sizeof(vx->current_runstate)))
+- return;
++ if (__put_user(vx->current_runstate, user_state))
++ goto out;
+
+ /*
+ * Write the actual runstate times immediately after the
+@@ -168,24 +188,23 @@ void kvm_xen_update_runstate_guest(struc
+ BUILD_BUG_ON(sizeof_field(struct vcpu_runstate_info, time) !=
+ sizeof(vx->runstate_times));
+
+- if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
+- &vx->runstate_times[0],
+- offset + sizeof(u64),
+- sizeof(vx->runstate_times)))
+- return;
+-
++ if (__copy_to_user(user_times + 1, vx->runstate_times, sizeof(vx->runstate_times)))
++ goto out;
+ smp_wmb();
+
+ /*
+ * Finally, clear the XEN_RUNSTATE_UPDATE bit in the guest's
+ * runstate_entry_time field.
+ */
+-
+ state_entry_time &= ~XEN_RUNSTATE_UPDATE;
+- if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
+- &state_entry_time, offset,
+- sizeof(state_entry_time)))
+- return;
++ __put_user(state_entry_time, user_times);
++ smp_wmb();
++
++ out:
++ mark_page_dirty_in_slot(v->kvm, ghc->memslot, ghc->gpa >> PAGE_SHIFT);
++
++ if (atomic)
++ pagefault_enable();
+ }
+
+ int __kvm_xen_has_interrupt(struct kvm_vcpu *v)
+@@ -337,6 +356,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcp
+ break;
+ }
+
++ /* It must fit within a single page */
++ if ((data->u.gpa & ~PAGE_MASK) + sizeof(struct vcpu_info) > PAGE_SIZE) {
++ r = -EINVAL;
++ break;
++ }
++
+ r = kvm_gfn_to_hva_cache_init(vcpu->kvm,
+ &vcpu->arch.xen.vcpu_info_cache,
+ data->u.gpa,
+@@ -354,6 +379,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcp
+ break;
+ }
+
++ /* It must fit within a single page */
++ if ((data->u.gpa & ~PAGE_MASK) + sizeof(struct pvclock_vcpu_time_info) > PAGE_SIZE) {
++ r = -EINVAL;
++ break;
++ }
++
+ r = kvm_gfn_to_hva_cache_init(vcpu->kvm,
+ &vcpu->arch.xen.vcpu_time_info_cache,
+ data->u.gpa,
+@@ -375,6 +406,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcp
+ break;
+ }
+
++ /* It must fit within a single page */
++ if ((data->u.gpa & ~PAGE_MASK) + sizeof(struct vcpu_runstate_info) > PAGE_SIZE) {
++ r = -EINVAL;
++ break;
++ }
++
+ r = kvm_gfn_to_hva_cache_init(vcpu->kvm,
+ &vcpu->arch.xen.runstate_cache,
+ data->u.gpa,
revert-module-async-async_synchronize_full-on-module.patch
gcc-plugins-stackleak-use-noinstr-in-favor-of-notrac.patch
random-wake-up-dev-random-writers-after-zap.patch
+kvm-x86-xen-fix-runstate-updates-to-be-atomic-when-preempting-vcpu.patch
+kvm-x86-nsvm-nvmx-set-nested_run_pending-on-vm-entry-which-is-a-result-of-rsm.patch
+kvm-x86-svm-don-t-passthrough-smap-smep-pke-bits-in-npt-gcr0.pg-case.patch
+kvm-x86-nsvm-fix-potential-null-derefernce-on-nested-migration.patch
+kvm-x86-nsvm-mark-vmcb01-as-dirty-when-restoring-smm-saved-state.patch
+iwlwifi-remove-deprecated-broadcast-filtering-feature.patch
+iwlwifi-fix-use-after-free.patch
+drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-external-bridge.patch
+drm-radeon-fix-backlight-control-on-imac-12-1.patch
+drm-atomic-don-t-pollute-crtc_state-mode_blob-with-error-pointers.patch
+drm-amd-pm-correct-the-sequence-of-sending-gpu-reset-msg.patch
+drm-amdgpu-skipping-sdma-hw_init-and-hw_fini-for-s0ix.patch
+drm-i915-opregion-check-port-number-bounds-for-swsci-display-power-state.patch
+drm-i915-fix-dbuf-slice-config-lookup.patch
+drm-i915-fix-mbus-join-config-lookup.patch