All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jarkko Sakkinen <jarkko@kernel.org>
To: Surendran Kanagaraj <surenkj@amazon.com>
Cc: Peter Huewe <peterhuewe@gmx.de>, Jason Gunthorpe <jgg@ziepe.ca>,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	nh-open-source@amazon.com, Alexander Graf <graf@amazon.de>,
	Gunnar Kudrjavets <gunnarku@amazon.com>,
	Josh Levinson <joshlev@amazon.com>
Subject: Re: [PATCH 1/2] tpm: Add per-chip timeout for transient unavailability
Date: Fri, 25 Sep 2026 19:03:10 +0300	[thread overview]
Message-ID: <arabPv2YCddSMu_b@kernel.org> (raw)
In-Reply-To: <20260923142834.16786-2-surenkj@amazon.com>

On Wed, Sep 23, 2026 at 02:28:33PM +0000, Surendran Kanagaraj wrote:
> TPM commands need to complete within the command duration defined
> in the TPM2 spec or to keep answering TPM2_RC_RETRY for at most
> TPM2_DURATION_LONG (2s).
> 
> Devices that have different timeout requirements than the TPM2 spec
> could exhaust the retry budget or exceed the command duration. These
> failures disable the device during an auth session, failing all
> subsequent TPM requests. Worse, when a TPM2_CC_FLUSH_CONTEXT command
> fails, it leaks the TPM's transient memory:
> 
>     tpm tpm0: in retry loop
>     tpm tpm0: tpm2_load_context: failed with a TPM error 0x0922
>     ...
>     tpm tpm0: A TPM error (2338) occurred flushing context
> 
> Fix this by adding chip->busy_timeout_ms to support devices that know
> the expected delay window. This value raises the TPM2_RC_RETRY retry
> budget and per-command durations to at least busy_timeout_ms. Chips
> that leave it at 0 keep the current timeouts. The driver sets it for
> NitroTPM in the following patch.
> 
> Tested with CONFIG_TCG_TPM2_HMAC=y and the following patch with the
> NitroTPM quirk applied, in QEMU with swtpm by stalling commands and
> holding the TPM in TPM2_RC_RETRY.
> 
> Assisted-by: LLM
> Signed-off-by: Surendran Kanagaraj <surenkj@amazon.com>
> ---
>  drivers/char/tpm/tpm-interface.c | 11 ++++++++---
>  drivers/char/tpm/tpm.h           |  2 +-
>  drivers/char/tpm/tpm2-cmd.c      | 17 ++++++++++++-----
>  include/linux/tpm.h              |  7 +++++++
>  4 files changed, 28 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 0bab78c8767c..a423395b201a 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -53,7 +53,7 @@ MODULE_PARM_DESC(suspend_pcr,
>  unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
>  {
>  	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> -		return tpm2_calc_ordinal_duration(ordinal);
> +		return tpm2_calc_ordinal_duration(chip, ordinal);
>  	else
>  		return tpm1_calc_ordinal_duration(chip, ordinal);
>  }
> @@ -213,7 +213,8 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
>   *
>   * A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from
>   * the TPM and retransmits the command after a delay up to a maximum wait of
> - * TPM2_DURATION_LONG.
> + * TPM2_DURATION_LONG, or chip->busy_timeout_ms when the driver declared a
> + * longer transient unavailability window.
>   *
>   * Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0
>   * only.
> @@ -228,6 +229,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz)
>  	/* space for header and handles */
>  	u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)];
>  	unsigned int delay_msec = TPM2_DURATION_SHORT;
> +	unsigned int max_delay_msec = TPM2_DURATION_LONG;
>  	u32 rc = 0;
>  	ssize_t ret;
>  	const size_t save_size = min(sizeof(save), bufsiz);
> @@ -241,6 +243,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz)
>  	 */
>  	memcpy(save, buf, save_size);
>  
> +	if (chip->busy_timeout_ms > max_delay_msec)
> +		max_delay_msec = chip->busy_timeout_ms;
> +
>  	for (;;) {
>  		ret = tpm_try_transmit(chip, buf, bufsiz);
>  		if (ret < 0)
> @@ -255,7 +260,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz)
>  		if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST)
>  			break;
>  
> -		if (delay_msec > TPM2_DURATION_LONG) {
> +		if (delay_msec > max_delay_msec) {
>  			if (rc == TPM2_RC_RETRY)
>  				dev_err(&chip->dev, "in retry loop\n");
>  			else
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index fa554c5ad80b..457eba8d03dd 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -119,7 +119,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
>  ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip);
>  int tpm2_auto_startup(struct tpm_chip *chip);
>  void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
> -unsigned long tpm2_calc_ordinal_duration(u32 ordinal);
> +unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
>  int tpm2_probe(struct tpm_chip *chip);
>  int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip);
>  int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> index ae22295df798..dc5ed57fefe1 100644
> --- a/drivers/char/tpm/tpm2-cmd.c
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -78,20 +78,27 @@ static const struct {
>  
>  /**
>   * tpm2_calc_ordinal_duration() - Calculate the maximum command duration
> + * @chip:	TPM chip to use.
>   * @ordinal: TPM command ordinal.
>   *
>   * Returns the maximum amount of time the chip is expected by kernel to
> - * take in jiffies.
> + * take in jiffies. The duration is never lower than chip->busy_timeout_ms.
>   */
> -unsigned long tpm2_calc_ordinal_duration(u32 ordinal)
> +unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
>  {
> +	unsigned long duration = TPM2_DURATION_DEFAULT;
>  	int i;
>  
>  	for (i = 0; i < ARRAY_SIZE(tpm2_ordinal_duration_map); i++)
> -		if (ordinal == tpm2_ordinal_duration_map[i].ordinal)
> -			return msecs_to_jiffies(tpm2_ordinal_duration_map[i].duration);
> +		if (ordinal == tpm2_ordinal_duration_map[i].ordinal) {
> +			duration = tpm2_ordinal_duration_map[i].duration;
> +			break;
> +		}
> +
> +	if (duration < chip->busy_timeout_ms)
> +		duration = chip->busy_timeout_ms;
>  
> -	return msecs_to_jiffies(TPM2_DURATION_DEFAULT);
> +	return msecs_to_jiffies(duration);
>  }
>  
>  /**
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index 0db277af45c3..7089067412d3 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -140,6 +140,13 @@ struct tpm_chip {
>  	unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */
>  	bool duration_adjusted;
>  
> +	/*
> +	 * Longest unavailability expected from the chip in ms. Raises the
> +	 * TPM2_RC_RETRY retry budget and the per-command durations to at
> +	 * least this value; 0 keeps the defaults.
> +	 */
> +	unsigned int busy_timeout_ms;

So I think this is a wrong solution.

Instead this should be tpm_crb internal and you should simply patch
chip->duration[]. See tpm_tis_core for example.

> +
>  	struct dentry *bios_dir;
>  
>  	const struct attribute_group *groups[3 + TPM_MAX_HASHES];
> -- 
> 2.47.3
> 

Br, Jarkko

  parent reply	other threads:[~2026-09-25 16:03 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-23 14:28 [PATCH 0/2] tpm: Handle transient NitroTPM unavailability Surendran Kanagaraj
2026-09-23 14:28 ` [PATCH 1/2] tpm: Add per-chip timeout for transient unavailability Surendran Kanagaraj
2026-09-25  9:04   ` Breno Leitao
2026-09-28 19:50     ` Surendran Kanagaraj
2026-09-29 22:15       ` Jarkko Sakkinen
2026-09-25 16:03   ` Jarkko Sakkinen [this message]
2026-09-29 13:21     ` Surendran Kanagaraj
2026-09-23 14:28 ` [PATCH 2/2] tpm_crb: Raise timeouts for Amazon NitroTPM Surendran Kanagaraj
2026-09-25 15:55   ` Jarkko Sakkinen
2026-09-28 21:09     ` Surendran Kanagaraj
2026-09-29 22:22       ` Jarkko Sakkinen
2026-09-30 19:15         ` Surendran Kanagaraj

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=arabPv2YCddSMu_b@kernel.org \
    --to=jarkko@kernel.org \
    --cc=graf@amazon.de \
    --cc=gunnarku@amazon.com \
    --cc=jgg@ziepe.ca \
    --cc=joshlev@amazon.com \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nh-open-source@amazon.com \
    --cc=peterhuewe@gmx.de \
    --cc=surenkj@amazon.com \
    /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.