--- /dev/null
+From 3d00827a90db6f79abc7cdc553887f89a2e0a184 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Svenning=20S=C3=B8rensen?= <sss@secomea.com>
+Date: Fri, 18 Feb 2022 11:27:01 +0000
+Subject: net: dsa: microchip: fix bridging with more than two member ports
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Svenning Sørensen <sss@secomea.com>
+
+commit 3d00827a90db6f79abc7cdc553887f89a2e0a184 upstream.
+
+Commit b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
+plugged a packet leak between ports that were members of different bridges.
+Unfortunately, this broke another use case, namely that of more than two
+ports that are members of the same bridge.
+
+After that commit, when a port is added to a bridge, hardware bridging
+between other member ports of that bridge will be cleared, preventing
+packet exchange between them.
+
+Fix by ensuring that the Port VLAN Membership bitmap includes any existing
+ports in the bridge, not just the port being added.
+
+Fixes: b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
+Signed-off-by: Svenning Sørensen <sss@secomea.com>
+Tested-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/dsa/microchip/ksz_common.c | 26 +++++++++++++++++++++++---
+ 1 file changed, 23 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/dsa/microchip/ksz_common.c
++++ b/drivers/net/dsa/microchip/ksz_common.c
+@@ -26,7 +26,7 @@ void ksz_update_port_member(struct ksz_d
+ struct dsa_switch *ds = dev->ds;
+ u8 port_member = 0, cpu_port;
+ const struct dsa_port *dp;
+- int i;
++ int i, j;
+
+ if (!dsa_is_user_port(ds, port))
+ return;
+@@ -45,13 +45,33 @@ void ksz_update_port_member(struct ksz_d
+ continue;
+ if (!dp->bridge_dev || dp->bridge_dev != other_dp->bridge_dev)
+ continue;
++ if (other_p->stp_state != BR_STATE_FORWARDING)
++ continue;
+
+- if (other_p->stp_state == BR_STATE_FORWARDING &&
+- p->stp_state == BR_STATE_FORWARDING) {
++ if (p->stp_state == BR_STATE_FORWARDING) {
+ val |= BIT(port);
+ port_member |= BIT(i);
+ }
+
++ /* Retain port [i]'s relationship to other ports than [port] */
++ for (j = 0; j < ds->num_ports; j++) {
++ const struct dsa_port *third_dp;
++ struct ksz_port *third_p;
++
++ if (j == i)
++ continue;
++ if (j == port)
++ continue;
++ if (!dsa_is_user_port(ds, j))
++ continue;
++ third_p = &dev->ports[j];
++ if (third_p->stp_state != BR_STATE_FORWARDING)
++ continue;
++ third_dp = dsa_to_port(ds, j);
++ if (third_dp->bridge_dev == dp->bridge_dev)
++ val |= BIT(j);
++ }
++
+ dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
+ }
+
--- /dev/null
+From 68af28426b3ca1bf9ba21c7d8bdd0ff639e5134c Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Wed, 23 Feb 2022 11:52:37 -0600
+Subject: platform/x86: amd-pmc: Set QOS during suspend on CZN w/ timer wakeup
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+commit 68af28426b3ca1bf9ba21c7d8bdd0ff639e5134c upstream.
+
+commit 59348401ebed ("platform/x86: amd-pmc: Add special handling for
+timer based S0i3 wakeup") adds support for using another platform timer
+in lieu of the RTC which doesn't work properly on some systems. This path
+was validated and worked well before submission. During the 5.16-rc1 merge
+window other patches were merged that caused this to stop working properly.
+
+When this feature was used with 5.16-rc1 or later some OEM laptops with the
+matching firmware requirements from that commit would shutdown instead of
+program a timer based wakeup.
+
+This was bisected to commit 8d89835b0467 ("PM: suspend: Do not pause
+cpuidle in the suspend-to-idle path"). This wasn't supposed to cause any
+negative impacts and also tested well on both Intel and ARM platforms.
+However this changed the semantics of when CPUs are allowed to be in the
+deepest state. For the AMD systems in question it appears this causes a
+firmware crash for timer based wakeup.
+
+It's hypothesized to be caused by the `amd-pmc` driver sending `OS_HINT`
+and all the CPUs going into a deep state while the timer is still being
+programmed. It's likely a firmware bug, but to avoid it don't allow setting
+CPUs into the deepest state while using CZN timer wakeup path.
+
+If later it's discovered that this also occurs from "regular" suspends
+without a timer as well or on other silicon, this may be later expanded to
+run in the suspend path for more scenarios.
+
+Cc: stable@vger.kernel.org # 5.16+
+Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Link: https://lore.kernel.org/linux-acpi/BL1PR12MB51570F5BD05980A0DCA1F3F4E23A9@BL1PR12MB5157.namprd12.prod.outlook.com/T/#mee35f39c41a04b624700ab2621c795367f19c90e
+Fixes: 8d89835b0467 ("PM: suspend: Do not pause cpuidle in the suspend-to-idle path")
+Fixes: 23f62d7ab25b ("PM: sleep: Pause cpuidle later and resume it earlier during system transitions")
+Fixes: 59348401ebed ("platform/x86: amd-pmc: Add special handling for timer based S0i3 wakeup"
+Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Link: https://lore.kernel.org/r/20220223175237.6209-1-mario.limonciello@amd.com
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/amd-pmc.c | 34 ++++++++++++++++++++++++++++++----
+ 1 file changed, 30 insertions(+), 4 deletions(-)
+
+--- a/drivers/platform/x86/amd-pmc.c
++++ b/drivers/platform/x86/amd-pmc.c
+@@ -21,6 +21,7 @@
+ #include <linux/module.h>
+ #include <linux/pci.h>
+ #include <linux/platform_device.h>
++#include <linux/pm_qos.h>
+ #include <linux/rtc.h>
+ #include <linux/suspend.h>
+ #include <linux/seq_file.h>
+@@ -79,6 +80,9 @@
+ #define PMC_MSG_DELAY_MIN_US 50
+ #define RESPONSE_REGISTER_LOOP_MAX 20000
+
++/* QoS request for letting CPUs in idle states, but not the deepest */
++#define AMD_PMC_MAX_IDLE_STATE_LATENCY 3
++
+ #define SOC_SUBSYSTEM_IP_MAX 12
+ #define DELAY_MIN_US 2000
+ #define DELAY_MAX_US 3000
+@@ -123,6 +127,7 @@ struct amd_pmc_dev {
+ u8 rev;
+ struct device *dev;
+ struct mutex lock; /* generic mutex lock */
++ struct pm_qos_request amd_pmc_pm_qos_req;
+ #if IS_ENABLED(CONFIG_DEBUG_FS)
+ struct dentry *dbgfs_dir;
+ #endif /* CONFIG_DEBUG_FS */
+@@ -459,6 +464,14 @@ static int amd_pmc_verify_czn_rtc(struct
+ rc = rtc_alarm_irq_enable(rtc_device, 0);
+ dev_dbg(pdev->dev, "wakeup timer programmed for %lld seconds\n", duration);
+
++ /*
++ * Prevent CPUs from getting into deep idle states while sending OS_HINT
++ * which is otherwise generally safe to send when at least one of the CPUs
++ * is not in deep idle states.
++ */
++ cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req, AMD_PMC_MAX_IDLE_STATE_LATENCY);
++ wake_up_all_idle_cpus();
++
+ return rc;
+ }
+
+@@ -476,17 +489,24 @@ static int __maybe_unused amd_pmc_suspen
+ /* Activate CZN specific RTC functionality */
+ if (pdev->cpu_id == AMD_CPU_ID_CZN) {
+ rc = amd_pmc_verify_czn_rtc(pdev, &arg);
+- if (rc < 0)
+- return rc;
++ if (rc)
++ goto fail;
+ }
+
+ /* Dump the IdleMask before we send hint to SMU */
+ amd_pmc_idlemask_read(pdev, dev, NULL);
+ msg = amd_pmc_get_os_hint(pdev);
+ rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0);
+- if (rc)
++ if (rc) {
+ dev_err(pdev->dev, "suspend failed\n");
++ goto fail;
++ }
+
++ return 0;
++fail:
++ if (pdev->cpu_id == AMD_CPU_ID_CZN)
++ cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req,
++ PM_QOS_DEFAULT_VALUE);
+ return rc;
+ }
+
+@@ -507,7 +527,12 @@ static int __maybe_unused amd_pmc_resume
+ /* Dump the IdleMask to see the blockers */
+ amd_pmc_idlemask_read(pdev, dev, NULL);
+
+- return 0;
++ /* Restore the QoS request back to defaults if it was set */
++ if (pdev->cpu_id == AMD_CPU_ID_CZN)
++ cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req,
++ PM_QOS_DEFAULT_VALUE);
++
++ return rc;
+ }
+
+ static const struct dev_pm_ops amd_pmc_pm_ops = {
+@@ -597,6 +622,7 @@ static int amd_pmc_probe(struct platform
+ amd_pmc_get_smu_version(dev);
+ platform_set_drvdata(pdev, dev);
+ amd_pmc_dbgfs_register(dev);
++ cpu_latency_qos_add_request(&dev->amd_pmc_pm_qos_req, PM_QOS_DEFAULT_VALUE);
+ return 0;
+ }
+