--- /dev/null
+wifi-rtw89-8852b-adjust-quota-to-avoid-ser-l1-caused.patch
+usb-dwc3-fix-gadget-mode-suspend-interrupt-handler-i.patch
+tpm-tpm_tis-avoid-cache-incoherency-in-test-for-inte.patch
+tpm-tpm_tis-only-handle-supported-interrupts.patch
+tpm_tis-use-tpm_chip_-start-stop-decoration-inside-t.patch
+tpm-tpm_tis-startup-chip-before-testing-for-interrup.patch
+tpm-re-enable-tpm-chip-boostrapping-non-tpm_tis-tpm-.patch
+tpm-prevent-hwrng-from-activating-during-resume.patch
+zsmalloc-move-lru-update-from-zs_map_object-to-zs_ma.patch
--- /dev/null
+From de5046897a02437941da794b1fc27e7059f7aa16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Apr 2023 20:29:28 +0300
+Subject: tpm: Prevent hwrng from activating during resume
+
+From: Jarkko Sakkinen <jarkko@kernel.org>
+
+[ Upstream commit 99d46450625590d410f86fe4660a5eff7d3b8343 ]
+
+Set TPM_CHIP_FLAG_SUSPENDED in tpm_pm_suspend() and reset in
+tpm_pm_resume(). While the flag is set, tpm_hwrng() gives back zero
+bytes. This prevents hwrng from racing during resume.
+
+Cc: stable@vger.kernel.org
+Fixes: 6e592a065d51 ("tpm: Move Linux RNG connection to hwrng")
+Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/tpm/tpm-chip.c | 4 ++++
+ drivers/char/tpm/tpm-interface.c | 10 ++++++++++
+ include/linux/tpm.h | 1 +
+ 3 files changed, 15 insertions(+)
+
+diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
+index 9c0a6aad81140..5be91591cb3b2 100644
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -572,6 +572,10 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+ {
+ struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
+
++ /* Give back zero bytes, as TPM chip has not yet fully resumed: */
++ if (chip->flags & TPM_CHIP_FLAG_SUSPENDED)
++ return 0;
++
+ return tpm_get_random(chip, data, max);
+ }
+
+diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
+index 7e513b7718320..0f941cb32eb17 100644
+--- a/drivers/char/tpm/tpm-interface.c
++++ b/drivers/char/tpm/tpm-interface.c
+@@ -412,6 +412,8 @@ int tpm_pm_suspend(struct device *dev)
+ }
+
+ suspended:
++ chip->flags |= TPM_CHIP_FLAG_SUSPENDED;
++
+ if (rc)
+ dev_err(dev, "Ignoring error %d while suspending\n", rc);
+ return 0;
+@@ -429,6 +431,14 @@ int tpm_pm_resume(struct device *dev)
+ if (chip == NULL)
+ return -ENODEV;
+
++ chip->flags &= ~TPM_CHIP_FLAG_SUSPENDED;
++
++ /*
++ * Guarantee that SUSPENDED is written last, so that hwrng does not
++ * activate before the chip has been fully resumed.
++ */
++ wmb();
++
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(tpm_pm_resume);
+diff --git a/include/linux/tpm.h b/include/linux/tpm.h
+index 77693389c3f9a..6a1e8f1572551 100644
+--- a/include/linux/tpm.h
++++ b/include/linux/tpm.h
+@@ -282,6 +282,7 @@ enum tpm_chip_flags {
+ TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
+ TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED = BIT(6),
+ TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7),
++ TPM_CHIP_FLAG_SUSPENDED = BIT(8),
+ };
+
+ #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
+--
+2.39.2
+
--- /dev/null
+From 083c65c6f80f05b42ee5c34664a80bf979381d75 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Apr 2023 21:49:37 +0300
+Subject: tpm: Re-enable TPM chip boostrapping non-tpm_tis TPM drivers
+
+From: Jarkko Sakkinen <jarkko@kernel.org>
+
+[ Upstream commit 0c8862de05c1a087795ee0a87bf61a6394306cc0 ]
+
+TPM chip bootstrapping was removed from tpm_chip_register(), and it
+was relocated to tpm_tis_core. This breaks all drivers which are not
+based on tpm_tis because the chip will not get properly initialized.
+
+Take the corrective steps:
+1. Rename tpm_chip_startup() as tpm_chip_bootstrap() and make it one-shot.
+2. Call tpm_chip_bootstrap() in tpm_chip_register(), which reverts the
+ things as tehy used to be.
+
+Cc: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+Fixes: 548eb516ec0f ("tpm, tpm_tis: startup chip before testing for interrupts")
+Reported-by: Pengfei Xu <pengfei.xu@intel.com>
+Link: https://lore.kernel.org/all/ZEjqhwHWBnxcaRV5@xpf.sh.intel.com/
+Tested-by: Pengfei Xu <pengfei.xu@intel.com>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Stable-dep-of: 99d464506255 ("tpm: Prevent hwrng from activating during resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/tpm/tpm-chip.c | 22 +++++++++++++++++++---
+ drivers/char/tpm/tpm.h | 2 +-
+ drivers/char/tpm/tpm_tis_core.c | 2 +-
+ include/linux/tpm.h | 13 +++++++------
+ 4 files changed, 28 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
+index 6fdfa65a00c37..9c0a6aad81140 100644
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -606,13 +606,19 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip)
+ }
+
+ /*
+- * tpm_chip_startup() - performs auto startup and allocates the PCRs
++ * tpm_chip_bootstrap() - Boostrap TPM chip after power on
+ * @chip: TPM chip to use.
++ *
++ * Initialize TPM chip after power on. This a one-shot function: subsequent
++ * calls will have no effect.
+ */
+-int tpm_chip_startup(struct tpm_chip *chip)
++int tpm_chip_bootstrap(struct tpm_chip *chip)
+ {
+ int rc;
+
++ if (chip->flags & TPM_CHIP_FLAG_BOOTSTRAPPED)
++ return 0;
++
+ rc = tpm_chip_start(chip);
+ if (rc)
+ return rc;
+@@ -625,9 +631,15 @@ int tpm_chip_startup(struct tpm_chip *chip)
+ stop:
+ tpm_chip_stop(chip);
+
++ /*
++ * Unconditionally set, as driver initialization should cease, when the
++ * boostrapping process fails.
++ */
++ chip->flags |= TPM_CHIP_FLAG_BOOTSTRAPPED;
++
+ return rc;
+ }
+-EXPORT_SYMBOL_GPL(tpm_chip_startup);
++EXPORT_SYMBOL_GPL(tpm_chip_bootstrap);
+
+ /*
+ * tpm_chip_register() - create a character device for the TPM chip
+@@ -644,6 +656,10 @@ int tpm_chip_register(struct tpm_chip *chip)
+ {
+ int rc;
+
++ rc = tpm_chip_bootstrap(chip);
++ if (rc)
++ return rc;
++
+ tpm_sysfs_add_device(chip);
+
+ tpm_bios_log_setup(chip);
+diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
+index 88d3bd76e0760..f6c99b3f00458 100644
+--- a/drivers/char/tpm/tpm.h
++++ b/drivers/char/tpm/tpm.h
+@@ -263,7 +263,7 @@ static inline void tpm_msleep(unsigned int delay_msec)
+ delay_msec * 1000);
+ };
+
+-int tpm_chip_startup(struct tpm_chip *chip);
++int tpm_chip_bootstrap(struct tpm_chip *chip);
+ int tpm_chip_start(struct tpm_chip *chip);
+ void tpm_chip_stop(struct tpm_chip *chip);
+ struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
+diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
+index 9f76c9a5aa422..f02b583005a53 100644
+--- a/drivers/char/tpm/tpm_tis_core.c
++++ b/drivers/char/tpm/tpm_tis_core.c
+@@ -1125,7 +1125,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+ init_waitqueue_head(&priv->read_queue);
+ init_waitqueue_head(&priv->int_queue);
+
+- rc = tpm_chip_startup(chip);
++ rc = tpm_chip_bootstrap(chip);
+ if (rc)
+ goto out_err;
+
+diff --git a/include/linux/tpm.h b/include/linux/tpm.h
+index 4dc97b9f65fb0..77693389c3f9a 100644
+--- a/include/linux/tpm.h
++++ b/include/linux/tpm.h
+@@ -274,13 +274,14 @@ enum tpm2_cc_attrs {
+ #define TPM_VID_ATML 0x1114
+
+ enum tpm_chip_flags {
+- TPM_CHIP_FLAG_TPM2 = BIT(1),
+- TPM_CHIP_FLAG_IRQ = BIT(2),
+- TPM_CHIP_FLAG_VIRTUAL = BIT(3),
+- TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
+- TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
++ TPM_CHIP_FLAG_BOOTSTRAPPED = BIT(0),
++ TPM_CHIP_FLAG_TPM2 = BIT(1),
++ TPM_CHIP_FLAG_IRQ = BIT(2),
++ TPM_CHIP_FLAG_VIRTUAL = BIT(3),
++ TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
++ TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
+ TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED = BIT(6),
+- TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7),
++ TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7),
+ };
+
+ #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
+--
+2.39.2
+
--- /dev/null
+From f035c8381e593048a921c503c776672fb183d04b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Nov 2022 14:55:25 +0100
+Subject: tpm, tpm_tis: Avoid cache incoherency in test for interrupts
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+
+[ Upstream commit 858e8b792d06f45c427897bd90205a1d90bf430f ]
+
+The interrupt handler that sets the boolean variable irq_tested may run on
+another CPU as the thread that checks irq_tested as part of the irq test in
+tpm_tis_send().
+
+Since nothing guarantees cache coherency between CPUs for unsynchronized
+accesses to boolean variables the testing thread might not perceive the
+value change done in the interrupt handler.
+
+Avoid this issue by setting the bit TPM_TIS_IRQ_TESTED in the flags field
+of the tpm_tis_data struct and by accessing this field with the bit
+manipulating functions that provide cache coherency.
+
+Also convert all other existing sites to use the proper macros when
+accessing this bitfield.
+
+Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+Tested-by: Michael Niewöhner <linux@mniewoehner.de>
+Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
+Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Stable-dep-of: 1398aa803f19 ("tpm_tis: Use tpm_chip_{start,stop} decoration inside tpm_tis_resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/tpm/tpm_tis.c | 2 +-
+ drivers/char/tpm/tpm_tis_core.c | 21 +++++++++++----------
+ drivers/char/tpm/tpm_tis_core.h | 2 +-
+ 3 files changed, 13 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
+index 4be19d8f3ca95..0d084d6652c41 100644
+--- a/drivers/char/tpm/tpm_tis.c
++++ b/drivers/char/tpm/tpm_tis.c
+@@ -243,7 +243,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
+ irq = tpm_info->irq;
+
+ if (itpm || is_itpm(ACPI_COMPANION(dev)))
+- phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND;
++ set_bit(TPM_TIS_ITPM_WORKAROUND, &phy->priv.flags);
+
+ return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
+ ACPI_HANDLE(dev));
+diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
+index eecfbd7e97867..6b05a84c3a206 100644
+--- a/drivers/char/tpm/tpm_tis_core.c
++++ b/drivers/char/tpm/tpm_tis_core.c
+@@ -376,7 +376,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
+ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+ int rc, status, burstcnt;
+ size_t count = 0;
+- bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;
++ bool itpm = test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
+
+ status = tpm_tis_status(chip);
+ if ((status & TPM_STS_COMMAND_READY) == 0) {
+@@ -509,7 +509,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+ int rc, irq;
+ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+
+- if (!(chip->flags & TPM_CHIP_FLAG_IRQ) || priv->irq_tested)
++ if (!(chip->flags & TPM_CHIP_FLAG_IRQ) ||
++ test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
+ return tpm_tis_send_main(chip, buf, len);
+
+ /* Verify receipt of the expected IRQ */
+@@ -519,11 +520,11 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+ rc = tpm_tis_send_main(chip, buf, len);
+ priv->irq = irq;
+ chip->flags |= TPM_CHIP_FLAG_IRQ;
+- if (!priv->irq_tested)
++ if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
+ tpm_msleep(1);
+- if (!priv->irq_tested)
++ if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
+ disable_interrupts(chip);
+- priv->irq_tested = true;
++ set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
+ return rc;
+ }
+
+@@ -666,7 +667,7 @@ static int probe_itpm(struct tpm_chip *chip)
+ size_t len = sizeof(cmd_getticks);
+ u16 vendor;
+
+- if (priv->flags & TPM_TIS_ITPM_WORKAROUND)
++ if (test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags))
+ return 0;
+
+ rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor);
+@@ -686,13 +687,13 @@ static int probe_itpm(struct tpm_chip *chip)
+
+ tpm_tis_ready(chip);
+
+- priv->flags |= TPM_TIS_ITPM_WORKAROUND;
++ set_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
+
+ rc = tpm_tis_send_data(chip, cmd_getticks, len);
+ if (rc == 0)
+ dev_info(&chip->dev, "Detected an iTPM.\n");
+ else {
+- priv->flags &= ~TPM_TIS_ITPM_WORKAROUND;
++ clear_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
+ rc = -EFAULT;
+ }
+
+@@ -736,7 +737,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
+ if (interrupt == 0)
+ return IRQ_NONE;
+
+- priv->irq_tested = true;
++ set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
+ if (interrupt & TPM_INTF_DATA_AVAIL_INT)
+ wake_up_interruptible(&priv->read_queue);
+ if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
+@@ -819,7 +820,7 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
+ if (rc < 0)
+ goto restore_irqs;
+
+- priv->irq_tested = false;
++ clear_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
+
+ /* Generate an interrupt by having the core call through to
+ * tpm_tis_send
+diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
+index 1d51d5168fb6e..4a58b870b4188 100644
+--- a/drivers/char/tpm/tpm_tis_core.h
++++ b/drivers/char/tpm/tpm_tis_core.h
+@@ -87,6 +87,7 @@ enum tpm_tis_flags {
+ TPM_TIS_ITPM_WORKAROUND = BIT(0),
+ TPM_TIS_INVALID_STATUS = BIT(1),
+ TPM_TIS_DEFAULT_CANCELLATION = BIT(2),
++ TPM_TIS_IRQ_TESTED = BIT(3),
+ };
+
+ struct tpm_tis_data {
+@@ -95,7 +96,6 @@ struct tpm_tis_data {
+ unsigned int locality_count;
+ int locality;
+ int irq;
+- bool irq_tested;
+ unsigned long flags;
+ void __iomem *ilb_base_addr;
+ u16 clkrun_enabled;
+--
+2.39.2
+
--- /dev/null
+From f8b479fb55f95efdfc06f09f858b22bf7bc9980f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Nov 2022 14:55:30 +0100
+Subject: tpm, tpm_tis: Only handle supported interrupts
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+
+[ Upstream commit e87fcf0dc2b47fac5b4824f00f74dfbcd4acd363 ]
+
+According to the TPM Interface Specification (TIS) support for "stsValid"
+and "commandReady" interrupts is only optional.
+This has to be taken into account when handling the interrupts in functions
+like wait_for_tpm_stat(). To determine the supported interrupts use the
+capability query.
+
+Also adjust wait_for_tpm_stat() to only wait for interrupt reported status
+changes. After that process all the remaining status changes by polling
+the status register.
+
+Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+Tested-by: Michael Niewöhner <linux@mniewoehner.de>
+Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
+Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Stable-dep-of: 1398aa803f19 ("tpm_tis: Use tpm_chip_{start,stop} decoration inside tpm_tis_resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/tpm/tpm_tis_core.c | 120 +++++++++++++++++++-------------
+ drivers/char/tpm/tpm_tis_core.h | 1 +
+ 2 files changed, 73 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
+index 6b05a84c3a206..a35c117ee7c80 100644
+--- a/drivers/char/tpm/tpm_tis_core.c
++++ b/drivers/char/tpm/tpm_tis_core.c
+@@ -53,41 +53,63 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
+ long rc;
+ u8 status;
+ bool canceled = false;
++ u8 sts_mask = 0;
++ int ret = 0;
+
+ /* check current status */
+ status = chip->ops->status(chip);
+ if ((status & mask) == mask)
+ return 0;
+
+- stop = jiffies + timeout;
++ /* check what status changes can be handled by irqs */
++ if (priv->int_mask & TPM_INTF_STS_VALID_INT)
++ sts_mask |= TPM_STS_VALID;
+
+- if (chip->flags & TPM_CHIP_FLAG_IRQ) {
++ if (priv->int_mask & TPM_INTF_DATA_AVAIL_INT)
++ sts_mask |= TPM_STS_DATA_AVAIL;
++
++ if (priv->int_mask & TPM_INTF_CMD_READY_INT)
++ sts_mask |= TPM_STS_COMMAND_READY;
++
++ sts_mask &= mask;
++
++ stop = jiffies + timeout;
++ /* process status changes with irq support */
++ if (sts_mask) {
++ ret = -ETIME;
+ again:
+ timeout = stop - jiffies;
+ if ((long)timeout <= 0)
+ return -ETIME;
+ rc = wait_event_interruptible_timeout(*queue,
+- wait_for_tpm_stat_cond(chip, mask, check_cancel,
++ wait_for_tpm_stat_cond(chip, sts_mask, check_cancel,
+ &canceled),
+ timeout);
+ if (rc > 0) {
+ if (canceled)
+ return -ECANCELED;
+- return 0;
++ ret = 0;
+ }
+ if (rc == -ERESTARTSYS && freezing(current)) {
+ clear_thread_flag(TIF_SIGPENDING);
+ goto again;
+ }
+- } else {
+- do {
+- usleep_range(priv->timeout_min,
+- priv->timeout_max);
+- status = chip->ops->status(chip);
+- if ((status & mask) == mask)
+- return 0;
+- } while (time_before(jiffies, stop));
+ }
++
++ if (ret)
++ return ret;
++
++ mask &= ~sts_mask;
++ if (!mask) /* all done */
++ return 0;
++ /* process status changes without irq support */
++ do {
++ status = chip->ops->status(chip);
++ if ((status & mask) == mask)
++ return 0;
++ usleep_range(priv->timeout_min,
++ priv->timeout_max);
++ } while (time_before(jiffies, stop));
+ return -ETIME;
+ }
+
+@@ -1032,8 +1054,40 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+ if (rc < 0)
+ goto out_err;
+
+- intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
+- TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
++ /* Figure out the capabilities */
++ rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps);
++ if (rc < 0)
++ goto out_err;
++
++ dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
++ intfcaps);
++ if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
++ dev_dbg(dev, "\tBurst Count Static\n");
++ if (intfcaps & TPM_INTF_CMD_READY_INT) {
++ intmask |= TPM_INTF_CMD_READY_INT;
++ dev_dbg(dev, "\tCommand Ready Int Support\n");
++ }
++ if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
++ dev_dbg(dev, "\tInterrupt Edge Falling\n");
++ if (intfcaps & TPM_INTF_INT_EDGE_RISING)
++ dev_dbg(dev, "\tInterrupt Edge Rising\n");
++ if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
++ dev_dbg(dev, "\tInterrupt Level Low\n");
++ if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
++ dev_dbg(dev, "\tInterrupt Level High\n");
++ if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) {
++ intmask |= TPM_INTF_LOCALITY_CHANGE_INT;
++ dev_dbg(dev, "\tLocality Change Int Support\n");
++ }
++ if (intfcaps & TPM_INTF_STS_VALID_INT) {
++ intmask |= TPM_INTF_STS_VALID_INT;
++ dev_dbg(dev, "\tSts Valid Int Support\n");
++ }
++ if (intfcaps & TPM_INTF_DATA_AVAIL_INT) {
++ intmask |= TPM_INTF_DATA_AVAIL_INT;
++ dev_dbg(dev, "\tData Avail Int Support\n");
++ }
++
+ intmask &= ~TPM_GLOBAL_INT_ENABLE;
+
+ rc = tpm_tis_request_locality(chip, 0);
+@@ -1067,32 +1121,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+ goto out_err;
+ }
+
+- /* Figure out the capabilities */
+- rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps);
+- if (rc < 0)
+- goto out_err;
+-
+- dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
+- intfcaps);
+- if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
+- dev_dbg(dev, "\tBurst Count Static\n");
+- if (intfcaps & TPM_INTF_CMD_READY_INT)
+- dev_dbg(dev, "\tCommand Ready Int Support\n");
+- if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
+- dev_dbg(dev, "\tInterrupt Edge Falling\n");
+- if (intfcaps & TPM_INTF_INT_EDGE_RISING)
+- dev_dbg(dev, "\tInterrupt Edge Rising\n");
+- if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
+- dev_dbg(dev, "\tInterrupt Level Low\n");
+- if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
+- dev_dbg(dev, "\tInterrupt Level High\n");
+- if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
+- dev_dbg(dev, "\tLocality Change Int Support\n");
+- if (intfcaps & TPM_INTF_STS_VALID_INT)
+- dev_dbg(dev, "\tSts Valid Int Support\n");
+- if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
+- dev_dbg(dev, "\tData Avail Int Support\n");
+-
+ /* INTERRUPT Setup */
+ init_waitqueue_head(&priv->read_queue);
+ init_waitqueue_head(&priv->int_queue);
+@@ -1123,7 +1151,9 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+ else
+ tpm_tis_probe_irq(chip, intmask);
+
+- if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
++ if (chip->flags & TPM_CHIP_FLAG_IRQ) {
++ priv->int_mask = intmask;
++ } else {
+ dev_err(&chip->dev, FW_BUG
+ "TPM interrupt not working, polling instead\n");
+
+@@ -1170,13 +1200,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
+ if (rc < 0)
+ goto out;
+
+- rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
+- if (rc < 0)
+- goto out;
+-
+- intmask |= TPM_INTF_CMD_READY_INT
+- | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
+- | TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
++ intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE;
+
+ tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
+
+diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
+index 4a58b870b4188..e978f457fd4d4 100644
+--- a/drivers/char/tpm/tpm_tis_core.h
++++ b/drivers/char/tpm/tpm_tis_core.h
+@@ -96,6 +96,7 @@ struct tpm_tis_data {
+ unsigned int locality_count;
+ int locality;
+ int irq;
++ unsigned int int_mask;
+ unsigned long flags;
+ void __iomem *ilb_base_addr;
+ u16 clkrun_enabled;
+--
+2.39.2
+
--- /dev/null
+From f3f4e16e311a02e7eef98e3a71e813567019a8ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Nov 2022 14:55:37 +0100
+Subject: tpm, tpm_tis: startup chip before testing for interrupts
+
+From: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+
+[ Upstream commit 548eb516ec0f7a484a23a902835899341164b8ea ]
+
+In tpm_tis_gen_interrupt() a request for a property value is sent to the
+TPM to test if interrupts are generated. However after a power cycle the
+TPM responds with TPM_RC_INITIALIZE which indicates that the TPM is not
+yet properly initialized.
+Fix this by first starting the TPM up before the request is sent. For this
+the startup implementation is removed from tpm_chip_register() and put
+into the new function tpm_chip_startup() which is called before the
+interrupts are tested.
+
+Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
+Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Stable-dep-of: 99d464506255 ("tpm: Prevent hwrng from activating during resume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/tpm/tpm-chip.c | 38 +++++++++++++++++++++------------
+ drivers/char/tpm/tpm.h | 1 +
+ drivers/char/tpm/tpm_tis_core.c | 5 +++++
+ 3 files changed, 30 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
+index 2a05d8cc0e795..6fdfa65a00c37 100644
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -605,6 +605,30 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip)
+ return rc;
+ }
+
++/*
++ * tpm_chip_startup() - performs auto startup and allocates the PCRs
++ * @chip: TPM chip to use.
++ */
++int tpm_chip_startup(struct tpm_chip *chip)
++{
++ int rc;
++
++ rc = tpm_chip_start(chip);
++ if (rc)
++ return rc;
++
++ rc = tpm_auto_startup(chip);
++ if (rc)
++ goto stop;
++
++ rc = tpm_get_pcr_allocation(chip);
++stop:
++ tpm_chip_stop(chip);
++
++ return rc;
++}
++EXPORT_SYMBOL_GPL(tpm_chip_startup);
++
+ /*
+ * tpm_chip_register() - create a character device for the TPM chip
+ * @chip: TPM chip to use.
+@@ -620,20 +644,6 @@ int tpm_chip_register(struct tpm_chip *chip)
+ {
+ int rc;
+
+- rc = tpm_chip_start(chip);
+- if (rc)
+- return rc;
+- rc = tpm_auto_startup(chip);
+- if (rc) {
+- tpm_chip_stop(chip);
+- return rc;
+- }
+-
+- rc = tpm_get_pcr_allocation(chip);
+- tpm_chip_stop(chip);
+- if (rc)
+- return rc;
+-
+ tpm_sysfs_add_device(chip);
+
+ tpm_bios_log_setup(chip);
+diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
+index 830014a266090..88d3bd76e0760 100644
+--- a/drivers/char/tpm/tpm.h
++++ b/drivers/char/tpm/tpm.h
+@@ -263,6 +263,7 @@ static inline void tpm_msleep(unsigned int delay_msec)
+ delay_msec * 1000);
+ };
+
++int tpm_chip_startup(struct tpm_chip *chip);
+ int tpm_chip_start(struct tpm_chip *chip);
+ void tpm_chip_stop(struct tpm_chip *chip);
+ struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
+diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
+index a5c22fb4ad428..9f76c9a5aa422 100644
+--- a/drivers/char/tpm/tpm_tis_core.c
++++ b/drivers/char/tpm/tpm_tis_core.c
+@@ -1124,6 +1124,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+ /* INTERRUPT Setup */
+ init_waitqueue_head(&priv->read_queue);
+ init_waitqueue_head(&priv->int_queue);
++
++ rc = tpm_chip_startup(chip);
++ if (rc)
++ goto out_err;
++
+ if (irq != -1) {
+ /*
+ * Before doing irq testing issue a command to the TPM in polling mode
+--
+2.39.2
+
--- /dev/null
+From bbf9bb3ea7787de45d6adbab39375b987643c8f3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Apr 2023 20:29:27 +0300
+Subject: tpm_tis: Use tpm_chip_{start,stop} decoration inside tpm_tis_resume
+
+From: Jarkko Sakkinen <jarkko@kernel.org>
+
+[ Upstream commit 1398aa803f198b7a386fdd8404666043e95f4c16 ]
+
+Before sending a TPM command, CLKRUN protocol must be disabled. This is not
+done in the case of tpm1_do_selftest() call site inside tpm_tis_resume().
+
+Address this by decorating the calls with tpm_chip_{start,stop}, which
+should be always used to arm and disarm the TPM chip for transmission.
+
+Finally, move the call to the main TPM driver callback as the last step
+because it should arm the chip by itself, if it needs that type of
+functionality.
+
+Cc: stable@vger.kernel.org
+Reported-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Closes: https://lore.kernel.org/linux-integrity/CS68AWILHXS4.3M36M1EKZLUMS@suppilovahvero/
+Fixes: a3fbfae82b4c ("tpm: take TPM chip power gating out of tpm_transmit()")
+Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
+Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/char/tpm/tpm_tis_core.c | 43 +++++++++++++++------------------
+ 1 file changed, 19 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
+index a35c117ee7c80..a5c22fb4ad428 100644
+--- a/drivers/char/tpm/tpm_tis_core.c
++++ b/drivers/char/tpm/tpm_tis_core.c
+@@ -1190,25 +1190,20 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
+ u32 intmask;
+ int rc;
+
+- if (chip->ops->clk_enable != NULL)
+- chip->ops->clk_enable(chip, true);
+-
+- /* reenable interrupts that device may have lost or
+- * BIOS/firmware may have disabled
++ /*
++ * Re-enable interrupts that device may have lost or BIOS/firmware may
++ * have disabled.
+ */
+ rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq);
+- if (rc < 0)
+- goto out;
++ if (rc < 0) {
++ dev_err(&chip->dev, "Setting IRQ failed.\n");
++ return;
++ }
+
+ intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE;
+-
+- tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
+-
+-out:
+- if (chip->ops->clk_enable != NULL)
+- chip->ops->clk_enable(chip, false);
+-
+- return;
++ rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
++ if (rc < 0)
++ dev_err(&chip->dev, "Enabling interrupts failed.\n");
+ }
+
+ int tpm_tis_resume(struct device *dev)
+@@ -1216,27 +1211,27 @@ int tpm_tis_resume(struct device *dev)
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ int ret;
+
+- ret = tpm_tis_request_locality(chip, 0);
+- if (ret < 0)
++ ret = tpm_chip_start(chip);
++ if (ret)
+ return ret;
+
+ if (chip->flags & TPM_CHIP_FLAG_IRQ)
+ tpm_tis_reenable_interrupts(chip);
+
+- ret = tpm_pm_resume(dev);
+- if (ret)
+- goto out;
+-
+ /*
+ * TPM 1.2 requires self-test on resume. This function actually returns
+ * an error code but for unknown reason it isn't handled.
+ */
+ if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
+ tpm1_do_selftest(chip);
+-out:
+- tpm_tis_relinquish_locality(chip, 0);
+
+- return ret;
++ tpm_chip_stop(chip);
++
++ ret = tpm_pm_resume(dev);
++ if (ret)
++ return ret;
++
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(tpm_tis_resume);
+ #endif
+--
+2.39.2
+
--- /dev/null
+From 426d034028687092d05d8e3c942768551b6cd2a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 May 2023 08:45:24 +0800
+Subject: usb: dwc3: fix gadget mode suspend interrupt handler issue
+
+From: Linyu Yuan <quic_linyyuan@quicinc.com>
+
+[ Upstream commit 4e8ef34e36f2839ef8c8da521ab7035956436818 ]
+
+When work in gadget mode, currently driver doesn't update software level
+link_state correctly as link state change event is not enabled for most
+devices, in function dwc3_gadget_suspend_interrupt(), it will only pass
+suspend event to UDC core when software level link state changes, so when
+interrupt generated in sequences of suspend -> reset -> conndone ->
+suspend, link state is not updated during reset and conndone, so second
+suspend interrupt event will not pass to UDC core.
+
+Remove link_state compare in dwc3_gadget_suspend_interrupt() and add a
+suspended flag to replace the compare function.
+
+Fixes: 799e9dc82968 ("usb: dwc3: gadget: conditionally disable Link State change events")
+Cc: stable <stable@kernel.org>
+Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
+Link: https://lore.kernel.org/r/20230512004524.31950-1-quic_linyyuan@quicinc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/dwc3/core.h | 2 ++
+ drivers/usb/dwc3/gadget.c | 10 +++++++++-
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
+index 4743e918dcafa..54ce9907a408c 100644
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -1110,6 +1110,7 @@ struct dwc3_scratchpad_array {
+ * 3 - Reserved
+ * @dis_metastability_quirk: set to disable metastability quirk.
+ * @dis_split_quirk: set to disable split boundary.
++ * @suspended: set to track suspend event due to U3/L2.
+ * @imod_interval: set the interrupt moderation interval in 250ns
+ * increments or 0 to disable.
+ * @max_cfg_eps: current max number of IN eps used across all USB configs.
+@@ -1327,6 +1328,7 @@ struct dwc3 {
+
+ unsigned dis_split_quirk:1;
+ unsigned async_callbacks:1;
++ unsigned suspended:1;
+
+ u16 imod_interval;
+
+diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
+index 80ae308448451..1cf352fbe7039 100644
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -3838,6 +3838,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
+ {
+ int reg;
+
++ dwc->suspended = false;
++
+ dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+@@ -3869,6 +3871,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+ {
+ u32 reg;
+
++ dwc->suspended = false;
++
+ /*
+ * Ideally, dwc3_reset_gadget() would trigger the function
+ * drivers to stop any active transfers through ep disable.
+@@ -4098,6 +4102,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+
+ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+ {
++ dwc->suspended = false;
++
+ /*
+ * TODO take core out of low power mode when that's
+ * implemented.
+@@ -4213,8 +4219,10 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
+ {
+ enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
+
+- if (dwc->link_state != next && next == DWC3_LINK_STATE_U3)
++ if (!dwc->suspended && next == DWC3_LINK_STATE_U3) {
++ dwc->suspended = true;
+ dwc3_suspend_gadget(dwc);
++ }
+
+ dwc->link_state = next;
+ }
+--
+2.39.2
+
--- /dev/null
+From b89eaa03f72e9a7ac42c36390e017e27e4e74f8c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Apr 2023 11:47:37 +0800
+Subject: wifi: rtw89: 8852b: adjust quota to avoid SER L1 caused by access
+ null page
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit c0426c446d92023d344131d01d929bc25db7a24e ]
+
+Though SER can recover this case, traffic can get stuck for a while. Fix it
+by adjusting page quota to avoid hardware access null page of CMAC/DMAC.
+
+Fixes: a1cb097168fa ("wifi: rtw89: 8852b: configure DLE mem")
+Fixes: 3e870b481733 ("wifi: rtw89: 8852b: add HFC quota arrays")
+Cc: stable@vger.kernel.org
+Tested-by: Larry Finger <Larry.Finger@lwfinger.net>
+Link: https://github.com/lwfinger/rtw89/issues/226#issuecomment-1520776761
+Link: https://github.com/lwfinger/rtw89/issues/240
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/20230426034737.24870-1-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/mac.c | 4 ++++
+ drivers/net/wireless/realtek/rtw89/mac.h | 2 ++
+ drivers/net/wireless/realtek/rtw89/rtw8852b.c | 22 +++++++++----------
+ 3 files changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
+index 2e2a2b6eab09d..d0cafe813cdb4 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac.c
++++ b/drivers/net/wireless/realtek/rtw89/mac.c
+@@ -1425,6 +1425,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
+ .wde_size4 = {RTW89_WDE_PG_64, 0, 4096,},
+ /* PCIE 64 */
+ .wde_size6 = {RTW89_WDE_PG_64, 512, 0,},
++ /* 8852B PCIE SCC */
++ .wde_size7 = {RTW89_WDE_PG_64, 510, 2,},
+ /* DLFW */
+ .wde_size9 = {RTW89_WDE_PG_64, 0, 1024,},
+ /* 8852C DLFW */
+@@ -1449,6 +1451,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
+ .wde_qt4 = {0, 0, 0, 0,},
+ /* PCIE 64 */
+ .wde_qt6 = {448, 48, 0, 16,},
++ /* 8852B PCIE SCC */
++ .wde_qt7 = {446, 48, 0, 16,},
+ /* 8852C DLFW */
+ .wde_qt17 = {0, 0, 0, 0,},
+ /* 8852C PCIE SCC */
+diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
+index 8064d3953d7f2..85c02c1f36bd7 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac.h
++++ b/drivers/net/wireless/realtek/rtw89/mac.h
+@@ -791,6 +791,7 @@ struct rtw89_mac_size_set {
+ const struct rtw89_dle_size wde_size0;
+ const struct rtw89_dle_size wde_size4;
+ const struct rtw89_dle_size wde_size6;
++ const struct rtw89_dle_size wde_size7;
+ const struct rtw89_dle_size wde_size9;
+ const struct rtw89_dle_size wde_size18;
+ const struct rtw89_dle_size wde_size19;
+@@ -803,6 +804,7 @@ struct rtw89_mac_size_set {
+ const struct rtw89_wde_quota wde_qt0;
+ const struct rtw89_wde_quota wde_qt4;
+ const struct rtw89_wde_quota wde_qt6;
++ const struct rtw89_wde_quota wde_qt7;
+ const struct rtw89_wde_quota wde_qt17;
+ const struct rtw89_wde_quota wde_qt18;
+ const struct rtw89_ple_quota ple_qt4;
+diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+index 45c374d025cbd..355e515364611 100644
+--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
++++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+@@ -13,25 +13,25 @@
+ #include "txrx.h"
+
+ static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_pcie[] = {
+- {5, 343, grp_0}, /* ACH 0 */
+- {5, 343, grp_0}, /* ACH 1 */
+- {5, 343, grp_0}, /* ACH 2 */
+- {5, 343, grp_0}, /* ACH 3 */
++ {5, 341, grp_0}, /* ACH 0 */
++ {5, 341, grp_0}, /* ACH 1 */
++ {4, 342, grp_0}, /* ACH 2 */
++ {4, 342, grp_0}, /* ACH 3 */
+ {0, 0, grp_0}, /* ACH 4 */
+ {0, 0, grp_0}, /* ACH 5 */
+ {0, 0, grp_0}, /* ACH 6 */
+ {0, 0, grp_0}, /* ACH 7 */
+- {4, 344, grp_0}, /* B0MGQ */
+- {4, 344, grp_0}, /* B0HIQ */
++ {4, 342, grp_0}, /* B0MGQ */
++ {4, 342, grp_0}, /* B0HIQ */
+ {0, 0, grp_0}, /* B1MGQ */
+ {0, 0, grp_0}, /* B1HIQ */
+ {40, 0, 0} /* FWCMDQ */
+ };
+
+ static const struct rtw89_hfc_pub_cfg rtw8852b_hfc_pubcfg_pcie = {
+- 448, /* Group 0 */
++ 446, /* Group 0 */
+ 0, /* Group 1 */
+- 448, /* Public Max */
++ 446, /* Public Max */
+ 0 /* WP threshold */
+ };
+
+@@ -44,9 +44,9 @@ static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_pcie[] = {
+ };
+
+ static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = {
+- [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6,
+- &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6,
+- &rtw89_mac_size.wde_qt6, &rtw89_mac_size.ple_qt18,
++ [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size7,
++ &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt7,
++ &rtw89_mac_size.wde_qt7, &rtw89_mac_size.ple_qt18,
+ &rtw89_mac_size.ple_qt58},
+ [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9,
+ &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4,
+--
+2.39.2
+
--- /dev/null
+From 6660a6be528d52babf342cc3d66bccd4f55b9b46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 May 2023 11:50:54 -0700
+Subject: zsmalloc: move LRU update from zs_map_object() to zs_malloc()
+
+From: Nhat Pham <nphamcs@gmail.com>
+
+[ Upstream commit d461aac924b937bcb4fd0ca1242b3ef6868ecddd ]
+
+Under memory pressure, we sometimes observe the following crash:
+
+[ 5694.832838] ------------[ cut here ]------------
+[ 5694.842093] list_del corruption, ffff888014b6a448->next is LIST_POISON1 (dead000000000100)
+[ 5694.858677] WARNING: CPU: 33 PID: 418824 at lib/list_debug.c:47 __list_del_entry_valid+0x42/0x80
+[ 5694.961820] CPU: 33 PID: 418824 Comm: fuse_counters.s Kdump: loaded Tainted: G S 5.19.0-0_fbk3_rc3_hoangnhatpzsdynshrv41_10870_g85a9558a25de #1
+[ 5694.990194] Hardware name: Wiwynn Twin Lakes MP/Twin Lakes Passive MP, BIOS YMM16 05/24/2021
+[ 5695.007072] RIP: 0010:__list_del_entry_valid+0x42/0x80
+[ 5695.017351] Code: 08 48 83 c2 22 48 39 d0 74 24 48 8b 10 48 39 f2 75 2c 48 8b 51 08 b0 01 48 39 f2 75 34 c3 48 c7 c7 55 d7 78 82 e8 4e 45 3b 00 <0f> 0b eb 31 48 c7 c7 27 a8 70 82 e8 3e 45 3b 00 0f 0b eb 21 48 c7
+[ 5695.054919] RSP: 0018:ffffc90027aef4f0 EFLAGS: 00010246
+[ 5695.065366] RAX: 41fe484987275300 RBX: ffff888008988180 RCX: 0000000000000000
+[ 5695.079636] RDX: ffff88886006c280 RSI: ffff888860060480 RDI: ffff888860060480
+[ 5695.093904] RBP: 0000000000000002 R08: 0000000000000000 R09: ffffc90027aef370
+[ 5695.108175] R10: 0000000000000000 R11: ffffffff82fdf1c0 R12: 0000000010000002
+[ 5695.122447] R13: ffff888014b6a448 R14: ffff888014b6a420 R15: 00000000138dc240
+[ 5695.136717] FS: 00007f23a7d3f740(0000) GS:ffff888860040000(0000) knlGS:0000000000000000
+[ 5695.152899] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 5695.164388] CR2: 0000560ceaab6ac0 CR3: 000000001c06c001 CR4: 00000000007706e0
+[ 5695.178659] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[ 5695.192927] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+[ 5695.207197] PKRU: 55555554
+[ 5695.212602] Call Trace:
+[ 5695.217486] <TASK>
+[ 5695.221674] zs_map_object+0x91/0x270
+[ 5695.229000] zswap_frontswap_store+0x33d/0x870
+[ 5695.237885] ? do_raw_spin_lock+0x5d/0xa0
+[ 5695.245899] __frontswap_store+0x51/0xb0
+[ 5695.253742] swap_writepage+0x3c/0x60
+[ 5695.261063] shrink_page_list+0x738/0x1230
+[ 5695.269255] shrink_lruvec+0x5ec/0xcd0
+[ 5695.276749] ? shrink_slab+0x187/0x5f0
+[ 5695.284240] ? mem_cgroup_iter+0x6e/0x120
+[ 5695.292255] shrink_node+0x293/0x7b0
+[ 5695.299402] do_try_to_free_pages+0xea/0x550
+[ 5695.307940] try_to_free_pages+0x19a/0x490
+[ 5695.316126] __folio_alloc+0x19ff/0x3e40
+[ 5695.323971] ? __filemap_get_folio+0x8a/0x4e0
+[ 5695.332681] ? walk_component+0x2a8/0xb50
+[ 5695.340697] ? generic_permission+0xda/0x2a0
+[ 5695.349231] ? __filemap_get_folio+0x8a/0x4e0
+[ 5695.357940] ? walk_component+0x2a8/0xb50
+[ 5695.365955] vma_alloc_folio+0x10e/0x570
+[ 5695.373796] ? walk_component+0x52/0xb50
+[ 5695.381634] wp_page_copy+0x38c/0xc10
+[ 5695.388953] ? filename_lookup+0x378/0xbc0
+[ 5695.397140] handle_mm_fault+0x87f/0x1800
+[ 5695.405157] do_user_addr_fault+0x1bd/0x570
+[ 5695.413520] exc_page_fault+0x5d/0x110
+[ 5695.421017] asm_exc_page_fault+0x22/0x30
+
+After some investigation, I have found the following issue: unlike other
+zswap backends, zsmalloc performs the LRU list update at the object
+mapping time, rather than when the slot for the object is allocated.
+This deviation was discussed and agreed upon during the review process
+of the zsmalloc writeback patch series:
+
+https://lore.kernel.org/lkml/Y3flcAXNxxrvy3ZH@cmpxchg.org/
+
+Unfortunately, this introduces a subtle bug that occurs when there is a
+concurrent store and reclaim, which interleave as follows:
+
+zswap_frontswap_store() shrink_worker()
+ zs_malloc() zs_zpool_shrink()
+ spin_lock(&pool->lock) zs_reclaim_page()
+ zspage = find_get_zspage()
+ spin_unlock(&pool->lock)
+ spin_lock(&pool->lock)
+ zspage = list_first_entry(&pool->lru)
+ list_del(&zspage->lru)
+ zspage->lru.next = LIST_POISON1
+ zspage->lru.prev = LIST_POISON2
+ spin_unlock(&pool->lock)
+ zs_map_object()
+ spin_lock(&pool->lock)
+ if (!list_empty(&zspage->lru))
+ list_del(&zspage->lru)
+ CHECK_DATA_CORRUPTION(next == LIST_POISON1) /* BOOM */
+
+With the current upstream code, this issue rarely happens. zswap only
+triggers writeback when the pool is already full, at which point all
+further store attempts are short-circuited. This creates an implicit
+pseudo-serialization between reclaim and store. I am working on a new
+zswap shrinking mechanism, which makes interleaving reclaim and store
+more likely, exposing this bug.
+
+zbud and z3fold do not have this problem, because they perform the LRU
+list update in the alloc function, while still holding the pool's lock.
+This patch fixes the aforementioned bug by moving the LRU update back to
+zs_malloc(), analogous to zbud and z3fold.
+
+Link: https://lkml.kernel.org/r/20230505185054.2417128-1-nphamcs@gmail.com
+Fixes: 64f768c6b32e ("zsmalloc: add a LRU to zs_pool to keep track of zspages in LRU order")
+Signed-off-by: Nhat Pham <nphamcs@gmail.com>
+Suggested-by: Johannes Weiner <hannes@cmpxchg.org>
+Acked-by: Johannes Weiner <hannes@cmpxchg.org>
+Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Acked-by: Minchan Kim <minchan@kernel.org>
+Cc: Dan Streetman <ddstreet@ieee.org>
+Cc: Nitin Gupta <ngupta@vflare.org>
+Cc: Seth Jennings <sjenning@redhat.com>
+Cc: Vitaly Wool <vitaly.wool@konsulko.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/zsmalloc.c | 36 +++++++++---------------------------
+ 1 file changed, 9 insertions(+), 27 deletions(-)
+
+diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
+index 3aed46ab7e6cb..0d451b61573cb 100644
+--- a/mm/zsmalloc.c
++++ b/mm/zsmalloc.c
+@@ -1350,31 +1350,6 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ obj_to_location(obj, &page, &obj_idx);
+ zspage = get_zspage(page);
+
+-#ifdef CONFIG_ZPOOL
+- /*
+- * Move the zspage to front of pool's LRU.
+- *
+- * Note that this is swap-specific, so by definition there are no ongoing
+- * accesses to the memory while the page is swapped out that would make
+- * it "hot". A new entry is hot, then ages to the tail until it gets either
+- * written back or swaps back in.
+- *
+- * Furthermore, map is also called during writeback. We must not put an
+- * isolated page on the LRU mid-reclaim.
+- *
+- * As a result, only update the LRU when the page is mapped for write
+- * when it's first instantiated.
+- *
+- * This is a deviation from the other backends, which perform this update
+- * in the allocation function (zbud_alloc, z3fold_alloc).
+- */
+- if (mm == ZS_MM_WO) {
+- if (!list_empty(&zspage->lru))
+- list_del(&zspage->lru);
+- list_add(&zspage->lru, &pool->lru);
+- }
+-#endif
+-
+ /*
+ * migration cannot move any zpages in this zspage. Here, pool->lock
+ * is too heavy since callers would take some time until they calls
+@@ -1544,9 +1519,8 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp)
+ fix_fullness_group(class, zspage);
+ record_obj(handle, obj);
+ class_stat_inc(class, OBJ_USED, 1);
+- spin_unlock(&pool->lock);
+
+- return handle;
++ goto out;
+ }
+
+ spin_unlock(&pool->lock);
+@@ -1570,6 +1544,14 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp)
+
+ /* We completely set up zspage so mark them as movable */
+ SetZsPageMovable(pool, zspage);
++out:
++#ifdef CONFIG_ZPOOL
++ /* Add/move zspage to beginning of LRU */
++ if (!list_empty(&zspage->lru))
++ list_del(&zspage->lru);
++ list_add(&zspage->lru, &pool->lru);
++#endif
++
+ spin_unlock(&pool->lock);
+
+ return handle;
+--
+2.39.2
+