All of lore.kernel.org
 help / color / mirror / Atom feed
From: Surendran Kanagaraj <surenkj@amazon.com>
To: Jarkko Sakkinen <jarkko@kernel.org>, Peter Huewe <peterhuewe@gmx.de>
Cc: Jason Gunthorpe <jgg@ziepe.ca>, <linux-integrity@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, Jonathan Corbet <corbet@lwn.net>,
	<linux-doc@vger.kernel.org>, Jonathan McDowell <noodles@earth.li>,
	"Breno Leitao" <leitao@debian.org>, <nh-open-source@amazon.com>,
	Alexander Graf <graf@amazon.de>,
	Gunnar Kudrjavets <gunnarku@amazon.com>,
	Josh Levinson <joshlev@amazon.com>
Subject: [RFC PATCH v3 1/8] tpm: Add a single table for all TPM wait limits
Date: Thu, 12 Nov 2026 16:38:39 +0000	[thread overview]
Message-ID: <20261112163846.97654-2-surenkj@amazon.com> (raw)
In-Reply-To: <20261112163846.97654-1-surenkj@amazon.com>

Every TPM wait takes its limit from a different place. The interface
timeouts live in four jiffies fields, the TPM 1.x durations in an
array, the TPM 2.0 durations in a per-ordinal map and the retry bound
in a constant. A driver cannot see or adjust these values in one
place. Apart from few TPM1.x fixups, nothing bounds checks these values.
Also a driver can send a command before any timeout is set,
xen-tpmfront calls tpm_get_timeouts() from probe before anything has
set a timeout, so its TPM 1.x timeout query waits on the vTPM with a
TIMEOUT_C of zero.

Add struct tpm_limits with one entry per limit: the interface timeouts
TIMEOUT_A to TIMEOUT_D and the duration classes SHORT, MEDIUM, LONG,
LONG_LONG and DEFAULT. Each entry holds the value in microseconds, its
source (the defaults, the TPM or the driver) and whether validation
clamped it.

tpm_chip_alloc() fills the table with the larger of the TPM 1.x and
TPM 2.0 defaults, so a wait has a usable limit before the TPM is
queried. Once the family is known, tpm_limits_update() rebuilds the
table (next patch calls it from timing query) in a fixed order:
the family defaults, the values the TPM reported, the driver's new
->adjust_limits() hook, then validation. Validation applies a floor
and a ceiling, keeps SHORT to LONG_LONG in increasing order and
keeps DEFAULT no shorter than LONG.

The hook sets values with tpm_limits_driver_set() or from a quirk
table through tpm_limits_apply_quirks(). tpm_poll_timeout() waits on
a condition for a limit from the table. No limits are read from the
table yet. The following patches move them to it.

Signed-off-by: Surendran Kanagaraj <surenkj@amazon.com>
---
 drivers/char/tpm/Makefile     |   1 +
 drivers/char/tpm/tpm-chip.c   |   1 +
 drivers/char/tpm/tpm-limits.c | 368 ++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm.h        |  13 ++
 include/linux/tpm.h           |  54 +++++
 5 files changed, 437 insertions(+)
 create mode 100644 drivers/char/tpm/tpm-limits.c

diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 5b5cdc0d32e4..92f469218e15 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -12,6 +12,7 @@ tpm-y += tpm2-cmd.o
 tpm-y += tpmrm-dev.o
 tpm-y += tpm2-space.o
 tpm-y += tpm-sysfs.o
+tpm-y += tpm-limits.o
 tpm-y += eventlog/common.o
 tpm-y += eventlog/tpm1.o
 tpm-y += eventlog/tpm2.o
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 0be5dbfaa72e..11a050c43e10 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -319,6 +319,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
 	}
 
 	chip->locality = -1;
+	tpm_limits_init(chip);
 	return chip;
 
 out:
diff --git a/drivers/char/tpm/tpm-limits.c b/drivers/char/tpm/tpm-limits.c
new file mode 100644
index 000000000000..3fe5affa1522
--- /dev/null
+++ b/drivers/char/tpm/tpm-limits.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Handles time limits for a TPM chip.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+#include <linux/tpm_ptp.h>
+#include "tpm.h"
+
+/* Bounds for the limits */
+#define TPM_LIMIT_FLOOR_US	        (2 * TPM_POLL_DURATION_MAX_US)
+#define TPM_LIMIT_INTF_CEILING_US	(60 * USEC_PER_SEC)
+#define TPM_LIMIT_DURATION_CEILING_US	(30 * 60 * USEC_PER_SEC)
+
+#define TPM_POLL_START_US		100
+#define TPM_POLL_INTF_MAX_US		100
+#define TPM_POLL_DURATION_MAX_US	1000
+
+static const u32 tpm1_defaults[TPM_NR_LIMITS] = {
+	[TPM_LIMIT_A]		= TIS_SHORT_TIMEOUT * USEC_PER_MSEC,
+	[TPM_LIMIT_B]		= TIS_LONG_TIMEOUT * USEC_PER_MSEC,
+	[TPM_LIMIT_C]		= TIS_SHORT_TIMEOUT * USEC_PER_MSEC,
+	[TPM_LIMIT_D]		= TIS_SHORT_TIMEOUT * USEC_PER_MSEC,
+
+	[TPM_LIMIT_SHORT]	= 120 * USEC_PER_SEC,
+	[TPM_LIMIT_MEDIUM]	= 120 * USEC_PER_SEC,
+	[TPM_LIMIT_LONG]	= 120 * USEC_PER_SEC,
+	[TPM_LIMIT_LONG_LONG]	= 120 * USEC_PER_SEC,
+	[TPM_LIMIT_DEFAULT]	= 120 * USEC_PER_SEC,
+};
+
+static const u32 tpm2_defaults[TPM_NR_LIMITS] = {
+	[TPM_LIMIT_A]		= TPM2_TIMEOUT_A * USEC_PER_MSEC,
+	[TPM_LIMIT_B]		= TPM2_TIMEOUT_B * USEC_PER_MSEC,
+	[TPM_LIMIT_C]		= TPM2_TIMEOUT_C * USEC_PER_MSEC,
+	[TPM_LIMIT_D]		= TPM2_TIMEOUT_D * USEC_PER_MSEC,
+
+	[TPM_LIMIT_SHORT]	= 750 * USEC_PER_MSEC,
+	[TPM_LIMIT_MEDIUM]	= 2000 * USEC_PER_MSEC,
+	[TPM_LIMIT_LONG]	= 3000 * USEC_PER_MSEC,
+	[TPM_LIMIT_LONG_LONG]	= TPM2_DURATION_LONG_LONG * USEC_PER_MSEC,
+	[TPM_LIMIT_DEFAULT]	= TPM2_DURATION_DEFAULT * USEC_PER_MSEC,
+};
+
+static const char * const tpm_limit_names[TPM_NR_LIMITS] = {
+	[TPM_LIMIT_A]		= "timeout_a",
+	[TPM_LIMIT_B]		= "timeout_b",
+	[TPM_LIMIT_C]		= "timeout_c",
+	[TPM_LIMIT_D]		= "timeout_d",
+	[TPM_LIMIT_SHORT]	= "short",
+	[TPM_LIMIT_MEDIUM]	= "medium",
+	[TPM_LIMIT_LONG]	= "long",
+	[TPM_LIMIT_LONG_LONG]	= "long_long",
+	[TPM_LIMIT_DEFAULT]	= "default",
+};
+
+static const char * const tpm_limit_labels[TPM_NR_LIMITS] = {
+	[TPM_LIMIT_A]		= "TIMEOUT_A",
+	[TPM_LIMIT_B]		= "TIMEOUT_B",
+	[TPM_LIMIT_C]		= "TIMEOUT_C",
+	[TPM_LIMIT_D]		= "TIMEOUT_D",
+	[TPM_LIMIT_SHORT]	= "SHORT",
+	[TPM_LIMIT_MEDIUM]	= "MEDIUM",
+	[TPM_LIMIT_LONG]	= "LONG",
+	[TPM_LIMIT_LONG_LONG]	= "LONG_LONG",
+	[TPM_LIMIT_DEFAULT]	= "DEFAULT",
+};
+
+static const char * const tpm_limit_src_names[] = {
+	[TPM_LSRC_DEFAULT]	= "DEFAULT",
+	[TPM_LSRC_TPM]		= "TPM",
+	[TPM_LSRC_DRIVER]	= "DRIVER",
+};
+
+static u32 tpm_limits_default_us(enum tpm_family family, enum tpm_limit limit)
+{
+	switch (family) {
+	case TPM_FAMILY_1:
+		return tpm1_defaults[limit];
+	case TPM_FAMILY_2:
+		return tpm2_defaults[limit];
+	default:
+		return max(tpm1_defaults[limit], tpm2_defaults[limit]);
+	}
+}
+
+static u32 tpm_limits_ceiling_us(enum tpm_limit limit)
+{
+	if (TPM_LIMIT_INTF_MASK & BIT(limit))
+		return TPM_LIMIT_INTF_CEILING_US;
+
+	return TPM_LIMIT_DURATION_CEILING_US;
+}
+
+static void tpm_limits_store(struct tpm_limits *p, enum tpm_limit limit,
+			     u32 us, enum tpm_limit_src src, u32 flags)
+{
+	p->entry[limit].time_us = us;
+	p->entry[limit].src = src;
+	p->entry[limit].flags = flags;
+}
+
+static void tpm_limits_raise(struct tpm_limits *p, enum tpm_limit limit,
+			     u32 us)
+{
+	if (p->entry[limit].time_us < us) {
+		p->entry[limit].time_us = us;
+		p->entry[limit].flags |= TPM_LF_CLAMPED;
+	}
+}
+
+static void tpm_limits_stage_defaults(struct tpm_limits *p,
+				      enum tpm_family family)
+{
+	int limit;
+
+	memset(p, 0, sizeof(*p));
+	p->family = family;
+	for (limit = 0; limit < TPM_NR_LIMITS; limit++)
+		tpm_limits_store(p, limit,
+				 tpm_limits_default_us(family, limit),
+				 TPM_LSRC_DEFAULT, 0);
+}
+
+/* The values the TPM reported, in usecs; zero where it reported nothing. */
+static void tpm_limits_stage_reported(struct tpm_limits *p,
+				      const u32 *reported)
+{
+	int limit;
+
+	for (limit = 0; limit < TPM_NR_LIMITS; limit++) {
+		if (reported[limit])
+			tpm_limits_store(p, limit, reported[limit],
+					 TPM_LSRC_TPM, 0);
+	}
+}
+
+static void tpm_limits_stage_validate(struct tpm_limits *p)
+{
+	int limit;
+
+	for (limit = 0; limit < TPM_NR_LIMITS; limit++) {
+		struct tpm_limit_entry *e = &p->entry[limit];
+		u32 lo = TPM_LIMIT_FLOOR_US;
+		u32 hi = tpm_limits_ceiling_us(limit);
+
+		if (e->time_us < lo) {
+			e->time_us = lo;
+			e->flags |= TPM_LF_CLAMPED;
+		} else if (e->time_us > hi) {
+			e->time_us = hi;
+			e->flags |= TPM_LF_CLAMPED;
+		}
+	}
+
+	/*
+	 * Keep SHORT to LONG_LONG in increasing order, and DEFAULT no shorter
+	 * than LONG.
+	 */
+	for (limit = TPM_LIMIT_MEDIUM; limit <= TPM_LIMIT_LONG_LONG; limit++)
+		tpm_limits_raise(p, limit, p->entry[limit - 1].time_us);
+
+	tpm_limits_raise(p, TPM_LIMIT_DEFAULT,
+			 p->entry[TPM_LIMIT_LONG].time_us);
+}
+
+static void tpm_limits_commit(struct tpm_chip *chip,
+			      const struct tpm_limits *p)
+{
+	const struct tpm_limit_entry *e = p->entry;
+	int limit;
+
+	chip->limits = *p;
+
+	for (limit = 0; limit < TPM_NR_LIMITS; limit++)
+		dev_dbg(&chip->dev, "limit %s = %u us (%s%s)\n",
+			tpm_limit_names[limit], e[limit].time_us,
+			tpm_limit_src_names[e[limit].src],
+			e[limit].flags & TPM_LF_CLAMPED ? ", clamped" : "");
+}
+
+/**
+ * tpm_limits_init() - set the boot limits of a new chip
+ * @chip: the chip tpm_chip_alloc() is setting up
+ *
+ * The family is not known yet, so each limit gets the larger of the two
+ * families' defaults before validation applies.
+ * The driver's data is not attached yet, so its ->adjust_limits() hook first
+ * runs from tpm_limits_update().
+ */
+void tpm_limits_init(struct tpm_chip *chip)
+{
+	struct tpm_limits p;
+
+	tpm_limits_stage_defaults(&p, TPM_FAMILY_UNKNOWN);
+	tpm_limits_stage_validate(&p);
+	tpm_limits_commit(chip, &p);
+}
+
+/**
+ * tpm_limits_update() - build the limits once the TPM family is known
+ * @chip:	the TPM chip, started, with TPM_CHIP_FLAG_TPM2 set on TPM 2.0
+ * @reported:	TPM_NR_LIMITS values in usecs, indexed by enum tpm_limit,
+ *		zero where the TPM reported nothing; or NULL
+ *
+ * Runs the stages in order: the family defaults, @reported, the driver's
+ * ->adjust_limits() hook, then validation. The hook may send commands, so
+ * the chip must be started. Call it before the chip is registered or with
+ * tpm_mutex held, so that no command sees half-built limits.
+ */
+void tpm_limits_update(struct tpm_chip *chip, const u32 *reported)
+{
+	enum tpm_family family = chip->flags & TPM_CHIP_FLAG_TPM2 ?
+				 TPM_FAMILY_2 : TPM_FAMILY_1;
+	struct tpm_limits p;
+
+	tpm_limits_stage_defaults(&p, family);
+	if (reported)
+		tpm_limits_stage_reported(&p, reported);
+	if (chip->ops->adjust_limits)
+		chip->ops->adjust_limits(chip, &p);
+	tpm_limits_stage_validate(&p);
+	tpm_limits_commit(chip, &p);
+}
+
+/**
+ * tpm_limits_driver_set() - set a limit from a driver's ->adjust_limits() hook
+ * @p:		the limits the hook received
+ * @limit:	the limit to set
+ * @us:		the new value in microseconds
+ *
+ * Marks the driver as the source of @limit. Validation runs after the hook,
+ * so the value can still be clamped.
+ */
+void tpm_limits_driver_set(struct tpm_limits *p, enum tpm_limit limit, u32 us)
+{
+	if (WARN_ON_ONCE(limit >= TPM_NR_LIMITS))
+		return;
+
+	tpm_limits_store(p, limit, us, TPM_LSRC_DRIVER, 0);
+}
+EXPORT_SYMBOL_GPL(tpm_limits_driver_set);
+
+/**
+ * tpm_limits_apply_quirks() - apply the first matching quirk entry
+ * @p:		the limits the ->adjust_limits() hook received
+ * @quirks:	the driver's quirk table
+ * @n:		the number of entries in @quirks
+ * @id:		the device identity to match, as the driver defines it
+ *
+ * Applies the first entry whose id is @id. Each non-zero value in the entry
+ * is set as tpm_limits_driver_set() does.
+ */
+void tpm_limits_apply_quirks(struct tpm_limits *p,
+			     const struct tpm_limits_quirk *quirks, size_t n,
+			     u32 id)
+{
+	size_t i;
+	int limit;
+
+	for (i = 0; i < n; i++) {
+		if (quirks[i].id != id)
+			continue;
+
+		for (limit = 0; limit < TPM_NR_LIMITS; limit++) {
+			if (quirks[i].time_us[limit])
+				tpm_limits_driver_set(p, limit,
+						      quirks[i].time_us[limit]);
+		}
+		return;
+	}
+}
+EXPORT_SYMBOL_GPL(tpm_limits_apply_quirks);
+
+static u32 tpm_limits_us(struct tpm_chip *chip, enum tpm_limit limit)
+{
+	if (!chip)
+		return tpm_limits_default_us(TPM_FAMILY_UNKNOWN, limit);
+
+	return chip->limits.entry[limit].time_us;
+}
+
+static int tpm_poll(struct tpm_chip *chip, u32 timeout_us,
+		    enum tpm_limit limit,
+		    bool (*cond)(struct tpm_chip *chip, void *arg), void *arg)
+{
+	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
+	unsigned int max_us = TPM_POLL_INTF_MAX_US;
+	unsigned int delay = TPM_POLL_START_US;
+	const char *label = "fixed timeout";
+	const char *src = "CALLER";
+
+	might_sleep();
+
+	if (limit < TPM_NR_LIMITS && !(TPM_LIMIT_INTF_MASK & BIT(limit)))
+		max_us = TPM_POLL_DURATION_MAX_US;
+
+	for (;;) {
+		if (cond(chip, arg))
+			return 0;
+		if (ktime_after(ktime_get(), timeout))
+			break;
+
+		usleep_range(delay / 2, delay);
+		delay = min(delay * 2, max_us);
+	}
+
+	if (cond(chip, arg))
+		return 0;
+	if (!chip)
+		return -ETIME;
+
+	if (limit < TPM_NR_LIMITS) {
+		label = tpm_limit_labels[limit];
+		src = tpm_limit_src_names[chip->limits.entry[limit].src];
+	}
+	dev_warn_ratelimited(&chip->dev, "%s expired after %u us (source %s)\n",
+			     label, timeout_us, src);
+	return -ETIME;
+}
+
+/**
+ * tpm_poll_timeout() - poll a condition until it holds or a limit passes
+ * @chip:	the TPM chip, or NULL before tpm_chip_alloc()
+ * @limit:	the limit that bounds the wait
+ * @cond:	returns true once the wait is over
+ * @arg:	passed to @cond
+ *
+ * Drivers pass an interface timeout, TPM_LIMIT_A to TPM_LIMIT_D, and the core
+ * passes a command's execution limit. Without a chip, the larger of the two
+ * families' defaults applies, @cond gets a NULL @chip and nothing is printed
+ * on expiry. @cond is checked once more after the deadline, so a TPM that
+ * finished while the caller was descheduled does not time out.
+ *
+ * Return: 0 once @cond holds, -ETIME if @limit passes first, or -EINVAL for
+ * a limit out of range.
+ */
+int tpm_poll_timeout(struct tpm_chip *chip, enum tpm_limit limit,
+		     bool (*cond)(struct tpm_chip *chip, void *arg), void *arg)
+{
+	if (WARN_ON_ONCE(limit >= TPM_NR_LIMITS))
+		return -EINVAL;
+
+	return tpm_poll(chip, tpm_limits_us(chip, limit), limit, cond, arg);
+}
+EXPORT_SYMBOL_GPL(tpm_poll_timeout);
+
+/**
+ * tpm_poll_timeout_us() - poll a condition with a driver-chosen timeout
+ * @chip:	the TPM chip, or NULL before tpm_chip_alloc()
+ * @timeout_us:	the timeout in microseconds
+ * @cond:	returns true once the wait is over
+ * @arg:	passed to @cond
+ *
+ * For a wait no TCG spec names, such as a mailbox doorbell. Otherwise as
+ * tpm_poll_timeout().
+ *
+ * Return: 0 once @cond holds, or -ETIME if @timeout_us passes first.
+ */
+int tpm_poll_timeout_us(struct tpm_chip *chip, u32 timeout_us,
+			bool (*cond)(struct tpm_chip *chip, void *arg),
+			void *arg)
+{
+	return tpm_poll(chip, timeout_us, TPM_NR_LIMITS, cond, arg);
+}
+EXPORT_SYMBOL_GPL(tpm_poll_timeout_us);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index fa554c5ad80b..be88011f9618 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -75,6 +75,19 @@ ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
 int tpm1_get_random(struct tpm_chip *chip, u8 *out, size_t max);
 int tpm1_get_pcr_allocation(struct tpm_chip *chip);
 unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
+
+void tpm_limits_init(struct tpm_chip *chip);
+void tpm_limits_update(struct tpm_chip *chip, const u32 *reported);
+void tpm_limits_driver_set(struct tpm_limits *p, enum tpm_limit limit, u32 us);
+void tpm_limits_apply_quirks(struct tpm_limits *p,
+			     const struct tpm_limits_quirk *quirks, size_t n,
+			     u32 id);
+int tpm_poll_timeout(struct tpm_chip *chip, enum tpm_limit limit,
+		     bool (*cond)(struct tpm_chip *chip, void *arg), void *arg);
+int tpm_poll_timeout_us(struct tpm_chip *chip, u32 timeout_us,
+			bool (*cond)(struct tpm_chip *chip, void *arg),
+			void *arg);
+
 int tpm_pm_suspend(struct device *dev);
 int tpm_pm_resume(struct device *dev);
 int tpm_class_shutdown(struct device *dev);
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 0db277af45c3..5454d87f43ba 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -29,6 +29,7 @@
 #include <linux/tpm_buf.h>
 
 struct tpm_chip;
+struct tpm_limits;
 struct trusted_key_payload;
 struct trusted_key_options;
 /* opaque structure, holds auth session parameters like the session key */
@@ -52,6 +53,7 @@ struct tpm_class_ops {
 				unsigned long *timeout_cap);
 	void (*update_durations)(struct tpm_chip *chip,
 				 unsigned long *duration_cap);
+	void (*adjust_limits)(struct tpm_chip *chip, struct tpm_limits *p);
 	int (*go_idle)(struct tpm_chip *chip);
 	int (*cmd_ready)(struct tpm_chip *chip);
 	int (*request_locality)(struct tpm_chip *chip, int loc);
@@ -71,6 +73,56 @@ enum tpm_duration {
 	TPM_NUM_DURATIONS = TPM_UNDEFINED,
 };
 
+enum tpm_limit {
+	/* Interface handshake timeouts */
+	TPM_LIMIT_A,
+	TPM_LIMIT_B,
+	TPM_LIMIT_C,
+	TPM_LIMIT_D,
+
+	/* Command duration classes */
+	TPM_LIMIT_SHORT,
+	TPM_LIMIT_MEDIUM,
+	TPM_LIMIT_LONG,
+	TPM_LIMIT_LONG_LONG,
+	TPM_LIMIT_DEFAULT,
+
+	TPM_NR_LIMITS,
+};
+
+#define TPM_LIMIT_INTF_MASK		GENMASK(TPM_LIMIT_D, TPM_LIMIT_A)
+
+enum tpm_family {
+	TPM_FAMILY_1,		/* TPM 1.1 and 1.2 */
+	TPM_FAMILY_2,
+	TPM_FAMILY_UNKNOWN,
+};
+
+enum tpm_limit_src {
+	TPM_LSRC_DEFAULT,	/* default values */
+	TPM_LSRC_TPM,		/* reported by the TPM */
+	TPM_LSRC_DRIVER,	/* set by the driver */
+};
+
+#define TPM_LF_CLAMPED		BIT(0)	/* limit validation replaced the value */
+
+struct tpm_limit_entry {
+	u32 time_us;
+	enum tpm_limit_src src;
+	u32 flags;		/* TPM_LF_* */
+};
+
+struct tpm_limits {
+	enum tpm_family family;
+	struct tpm_limit_entry entry[TPM_NR_LIMITS];
+};
+
+/* per-device overrides based on id the driver defines e.g. DID/VID */
+struct tpm_limits_quirk {
+	u32 id;				/* driver-defined device identity */
+	u32 time_us[TPM_NR_LIMITS];	/* 0 leaves the limit alone */
+};
+
 #define TPM_PPI_VERSION_LEN		3
 
 struct tpm_space {
@@ -140,6 +192,8 @@ struct tpm_chip {
 	unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */
 	bool duration_adjusted;
 
+	struct tpm_limits limits;
+
 	struct dentry *bios_dir;
 
 	const struct attribute_group *groups[3 + TPM_MAX_HASHES];
-- 
2.47.3


  reply	other threads:[~2026-11-12 16:38 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-12 16:38 [RFC PATCH v3 0/8] tpm: Rework timeout and duration handling Surendran Kanagaraj
2026-11-12 16:38 ` Surendran Kanagaraj [this message]
2026-11-12 16:38 ` [RFC PATCH v3 2/8] tpm: Wire the timing setup to the limits table Surendran Kanagaraj
2026-11-12 16:38 ` [RFC PATCH v3 3/8] tpm: Take command durations from " Surendran Kanagaraj
2026-11-12 16:38 ` [RFC PATCH v3 4/8] tpm: Bound core and CRB waits by " Surendran Kanagaraj
2026-11-12 16:42 ` [RFC PATCH v3 5/8] tpm: Drop the jiffies timing fields from struct tpm_chip Surendran Kanagaraj
2026-11-12 16:43 ` [RFC PATCH v3 6/8] tpm: Add the tpm.limits= parameter Surendran Kanagaraj
2026-11-12 16:45 ` [RFC PATCH v3 7/8] tpm: Show timeouts and durations for TPM 2.0 chips Surendran Kanagaraj
2026-11-12 16:46 ` [RFC PATCH v3 8/8] tpm_crb: Raise the limits for Amazon NitroTPM Surendran Kanagaraj
2026-11-12 18:39 ` [RFC PATCH v3 0/8] tpm: Rework timeout and duration handling Jarkko Sakkinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261112163846.97654-2-surenkj@amazon.com \
    --to=surenkj@amazon.com \
    --cc=corbet@lwn.net \
    --cc=graf@amazon.de \
    --cc=gunnarku@amazon.com \
    --cc=jarkko@kernel.org \
    --cc=jgg@ziepe.ca \
    --cc=joshlev@amazon.com \
    --cc=leitao@debian.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nh-open-source@amazon.com \
    --cc=noodles@earth.li \
    --cc=peterhuewe@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.