From 1d1850776687003fbe71b45ff1e6e5e64e74dda0 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 25 May 2023 10:38:17 -0400 Subject: [PATCH] Fixes for 6.1 Signed-off-by: Sasha Levin --- queue-6.1/series | 7 + ...-hwrng-from-activating-during-resume.patch | 82 +++++++ ...m-chip-boostrapping-non-tpm_tis-tpm-.patch | 141 +++++++++++ ...d-cache-incoherency-in-test-for-inte.patch | 157 ++++++++++++ ...tis-only-handle-supported-interrupts.patch | 231 ++++++++++++++++++ ...tup-chip-before-testing-for-interrup.patch | 117 +++++++++ ...chip_-start-stop-decoration-inside-t.patch | 110 +++++++++ ...get-mode-suspend-interrupt-handler-i.patch | 98 ++++++++ 8 files changed, 943 insertions(+) create mode 100644 queue-6.1/series create mode 100644 queue-6.1/tpm-prevent-hwrng-from-activating-during-resume.patch create mode 100644 queue-6.1/tpm-re-enable-tpm-chip-boostrapping-non-tpm_tis-tpm-.patch create mode 100644 queue-6.1/tpm-tpm_tis-avoid-cache-incoherency-in-test-for-inte.patch create mode 100644 queue-6.1/tpm-tpm_tis-only-handle-supported-interrupts.patch create mode 100644 queue-6.1/tpm-tpm_tis-startup-chip-before-testing-for-interrup.patch create mode 100644 queue-6.1/tpm_tis-use-tpm_chip_-start-stop-decoration-inside-t.patch create mode 100644 queue-6.1/usb-dwc3-fix-gadget-mode-suspend-interrupt-handler-i.patch diff --git a/queue-6.1/series b/queue-6.1/series new file mode 100644 index 00000000000..f5a9a42d335 --- /dev/null +++ b/queue-6.1/series @@ -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 index 00000000000..0ac4d8ab901 --- /dev/null +++ b/queue-6.1/tpm-prevent-hwrng-from-activating-during-resume.patch @@ -0,0 +1,82 @@ +From e79fa075c1c2da808fc1a88c4303096bd82f5edb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Apr 2023 20:29:28 +0300 +Subject: tpm: Prevent hwrng from activating during resume + +From: Jarkko Sakkinen + +[ 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 +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..be9eccae6a4 --- /dev/null +++ b/queue-6.1/tpm-re-enable-tpm-chip-boostrapping-non-tpm_tis-tpm-.patch @@ -0,0 +1,141 @@ +From 32e4f6f93a5d560284471fc1cb66a1f2da00ae22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Apr 2023 21:49:37 +0300 +Subject: tpm: Re-enable TPM chip boostrapping non-tpm_tis TPM drivers + +From: Jarkko Sakkinen + +[ 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 +Fixes: 548eb516ec0f ("tpm, tpm_tis: startup chip before testing for interrupts") +Reported-by: Pengfei Xu +Link: https://lore.kernel.org/all/ZEjqhwHWBnxcaRV5@xpf.sh.intel.com/ +Tested-by: Pengfei Xu +Signed-off-by: Jarkko Sakkinen +Stable-dep-of: 99d464506255 ("tpm: Prevent hwrng from activating during resume") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..b5f45e87bc4 --- /dev/null +++ b/queue-6.1/tpm-tpm_tis-avoid-cache-incoherency-in-test-for-inte.patch @@ -0,0 +1,157 @@ +From 218a38abb0e374cd744da9e1f74794df60cff281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Michael Niewöhner +Tested-by: Jarkko Sakkinen +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Stable-dep-of: 1398aa803f19 ("tpm_tis: Use tpm_chip_{start,stop} decoration inside tpm_tis_resume") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..bcbc4b3e283 --- /dev/null +++ b/queue-6.1/tpm-tpm_tis-only-handle-supported-interrupts.patch @@ -0,0 +1,231 @@ +From 09f601a5866efe2f1a0e5cc00a568bf0eb69650f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Michael Niewöhner +Tested-by: Jarkko Sakkinen +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Stable-dep-of: 1398aa803f19 ("tpm_tis: Use tpm_chip_{start,stop} decoration inside tpm_tis_resume") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..78f4ce45179 --- /dev/null +++ b/queue-6.1/tpm-tpm_tis-startup-chip-before-testing-for-interrup.patch @@ -0,0 +1,117 @@ +From 0f09f9c0b3a701697482a285e93851c2ae90971b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 24 Nov 2022 14:55:37 +0100 +Subject: tpm, tpm_tis: startup chip before testing for interrupts + +From: Lino Sanfilippo + +[ 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 +Tested-by: Jarkko Sakkinen +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +Stable-dep-of: 99d464506255 ("tpm: Prevent hwrng from activating during resume") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..2b65f96c6a7 --- /dev/null +++ b/queue-6.1/tpm_tis-use-tpm_chip_-start-stop-decoration-inside-t.patch @@ -0,0 +1,110 @@ +From ab7381f1e48942238a61626d40d39f5cb2a0c69d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +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 +Signed-off-by: Jarkko Sakkinen +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..fe209194757 --- /dev/null +++ b/queue-6.1/usb-dwc3-fix-gadget-mode-suspend-interrupt-handler-i.patch @@ -0,0 +1,98 @@ +From 770e2d8a7c24ab5c9d35b653e58352cebf5b4954 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 May 2023 08:45:24 +0800 +Subject: usb: dwc3: fix gadget mode suspend interrupt handler issue + +From: Linyu Yuan + +[ 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 +Acked-by: Thinh Nguyen +Signed-off-by: Linyu Yuan +Link: https://lore.kernel.org/r/20230512004524.31950-1-quic_linyyuan@quicinc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 + -- 2.47.3