]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.1
authorSasha Levin <sashal@kernel.org>
Thu, 25 May 2023 14:38:17 +0000 (10:38 -0400)
committerSasha Levin <sashal@kernel.org>
Thu, 25 May 2023 14:38:17 +0000 (10:38 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.1/series [new file with mode: 0644]
queue-6.1/tpm-prevent-hwrng-from-activating-during-resume.patch [new file with mode: 0644]
queue-6.1/tpm-re-enable-tpm-chip-boostrapping-non-tpm_tis-tpm-.patch [new file with mode: 0644]
queue-6.1/tpm-tpm_tis-avoid-cache-incoherency-in-test-for-inte.patch [new file with mode: 0644]
queue-6.1/tpm-tpm_tis-only-handle-supported-interrupts.patch [new file with mode: 0644]
queue-6.1/tpm-tpm_tis-startup-chip-before-testing-for-interrup.patch [new file with mode: 0644]
queue-6.1/tpm_tis-use-tpm_chip_-start-stop-decoration-inside-t.patch [new file with mode: 0644]
queue-6.1/usb-dwc3-fix-gadget-mode-suspend-interrupt-handler-i.patch [new file with mode: 0644]

diff --git a/queue-6.1/series b/queue-6.1/series
new file mode 100644 (file)
index 0000000..f5a9a42
--- /dev/null
@@ -0,0 +1,7 @@
+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
diff --git a/queue-6.1/tpm-prevent-hwrng-from-activating-during-resume.patch b/queue-6.1/tpm-prevent-hwrng-from-activating-during-resume.patch
new file mode 100644 (file)
index 0000000..0ac4d8a
--- /dev/null
@@ -0,0 +1,82 @@
+From e79fa075c1c2da808fc1a88c4303096bd82f5edb 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 31d8074821524..95d847c9de79a 100644
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -568,6 +568,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 cea64d58ef9f7..4e22e4f4cec85 100644
+--- a/include/linux/tpm.h
++++ b/include/linux/tpm.h
+@@ -281,6 +281,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
+
diff --git a/queue-6.1/tpm-re-enable-tpm-chip-boostrapping-non-tpm_tis-tpm-.patch b/queue-6.1/tpm-re-enable-tpm-chip-boostrapping-non-tpm_tis-tpm-.patch
new file mode 100644 (file)
index 0000000..be9ecca
--- /dev/null
@@ -0,0 +1,141 @@
+From 32e4f6f93a5d560284471fc1cb66a1f2da00ae22 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 47c2861af45a3..31d8074821524 100644
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -602,13 +602,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;
+@@ -621,9 +627,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
+@@ -640,6 +652,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 dfeb25a0362de..cea64d58ef9f7 100644
+--- a/include/linux/tpm.h
++++ b/include/linux/tpm.h
+@@ -273,13 +273,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
+
diff --git a/queue-6.1/tpm-tpm_tis-avoid-cache-incoherency-in-test-for-inte.patch b/queue-6.1/tpm-tpm_tis-avoid-cache-incoherency-in-test-for-inte.patch
new file mode 100644 (file)
index 0000000..b5f45e8
--- /dev/null
@@ -0,0 +1,157 @@
+From 218a38abb0e374cd744da9e1f74794df60cff281 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
+
diff --git a/queue-6.1/tpm-tpm_tis-only-handle-supported-interrupts.patch b/queue-6.1/tpm-tpm_tis-only-handle-supported-interrupts.patch
new file mode 100644 (file)
index 0000000..bcbc4b3
--- /dev/null
@@ -0,0 +1,231 @@
+From 09f601a5866efe2f1a0e5cc00a568bf0eb69650f 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
+
diff --git a/queue-6.1/tpm-tpm_tis-startup-chip-before-testing-for-interrup.patch b/queue-6.1/tpm-tpm_tis-startup-chip-before-testing-for-interrup.patch
new file mode 100644 (file)
index 0000000..78f4ce4
--- /dev/null
@@ -0,0 +1,117 @@
+From 0f09f9c0b3a701697482a285e93851c2ae90971b 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 5165f6d3da228..47c2861af45a3 100644
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -601,6 +601,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.
+@@ -616,20 +640,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
+
diff --git a/queue-6.1/tpm_tis-use-tpm_chip_-start-stop-decoration-inside-t.patch b/queue-6.1/tpm_tis-use-tpm_chip_-start-stop-decoration-inside-t.patch
new file mode 100644 (file)
index 0000000..2b65f96
--- /dev/null
@@ -0,0 +1,110 @@
+From ab7381f1e48942238a61626d40d39f5cb2a0c69d 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
+
diff --git a/queue-6.1/usb-dwc3-fix-gadget-mode-suspend-interrupt-handler-i.patch b/queue-6.1/usb-dwc3-fix-gadget-mode-suspend-interrupt-handler-i.patch
new file mode 100644 (file)
index 0000000..fe20919
--- /dev/null
@@ -0,0 +1,98 @@
+From 770e2d8a7c24ab5c9d35b653e58352cebf5b4954 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 582ebd9cf9c2e..bb57bc9bc17cb 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 d12cb8f0d1f48..8cd0d919ef63d 100644
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -3828,6 +3828,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);
+@@ -3859,6 +3861,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.
+@@ -4088,6 +4092,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.
+@@ -4203,8 +4209,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
+