From: Prachotan Bathi Date: Tue, 8 Jul 2025 22:51:51 +0000 (-0500) Subject: tpm_crb_ffa: handle tpm busy return code X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7f0c6675b3194461ad7bb8db1d822445121fb029;p=thirdparty%2Flinux.git tpm_crb_ffa: handle tpm busy return code Platforms supporting direct message request v2 [1] can support secure partitions that support multiple services. For CRB over FF-A interface, if the firmware TPM or TPM service [1] shares its Secure Partition (SP) with another service, message requests may fail with a -EBUSY error. To handle this, replace the single check and call with a retry loop that attempts the TPM message send operation until it succeeds or a configurable timeout is reached. Implement a _try_send_receive function to do a single send/receive and modify the existing send_receive to add this retry loop. The retry mechanism introduces a module parameter (`busy_timeout_ms`, default: 2000ms) to control how long to keep retrying on -EBUSY responses. Between retries, the code waits briefly (50-100 microseconds) to avoid busy-waiting and handling TPM BUSY conditions more gracefully. The parameter can be modified at run-time as such: echo 3000 | tee /sys/module/tpm_crb_ffa/parameters/busy_timeout_ms This changes the timeout from the default 2000ms to 3000ms. [1] TPM Service Command Response Buffer Interface Over FF-A https://developer.arm.com/documentation/den0138/latest/ Signed-off-by: Prachotan Bathi Signed-off-by: Jarkko Sakkinen --- diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 07e22ba5bfe34..343377538fe97 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7214,6 +7214,14 @@ causing a major performance hit, and the space where machines are deployed is by other means guarded. + tpm_crb_ffa.busy_timeout_ms= [ARM64,TPM] + Maximum time in milliseconds to retry sending a message + to the TPM service before giving up. This parameter controls + how long the system will continue retrying when the TPM + service is busy. + Format: + Default: 2000 (2 seconds) + tpm_suspend_pcr=[HW,TPM] Format: integer pcr id Specify that at suspend time, the tpm driver diff --git a/drivers/char/tpm/tpm_crb_ffa.c b/drivers/char/tpm/tpm_crb_ffa.c index afa341946f4ed..755b77b32ea47 100644 --- a/drivers/char/tpm/tpm_crb_ffa.c +++ b/drivers/char/tpm/tpm_crb_ffa.c @@ -10,8 +10,16 @@ #define pr_fmt(fmt) "CRB_FFA: " fmt #include +#include +#include #include "tpm_crb_ffa.h" +static unsigned int busy_timeout_ms = 2000; + +module_param(busy_timeout_ms, uint, 0644); +MODULE_PARM_DESC(busy_timeout_ms, + "Maximum time in ms to retry before giving up on busy"); + /* TPM service function status codes */ #define CRB_FFA_OK 0x05000001 #define CRB_FFA_OK_RESULTS_RETURNED 0x05000002 @@ -189,17 +197,13 @@ int tpm_crb_ffa_init(void) } EXPORT_SYMBOL_GPL(tpm_crb_ffa_init); -static int __tpm_crb_ffa_send_receive(unsigned long func_id, - unsigned long a0, - unsigned long a1, - unsigned long a2) +static int __tpm_crb_ffa_try_send_receive(unsigned long func_id, + unsigned long a0, unsigned long a1, + unsigned long a2) { const struct ffa_msg_ops *msg_ops; int ret; - if (!tpm_crb_ffa) - return -ENOENT; - msg_ops = tpm_crb_ffa->ffa_dev->ops->msg_ops; if (ffa_partition_supports_direct_req2_recv(tpm_crb_ffa->ffa_dev)) { @@ -225,6 +229,33 @@ static int __tpm_crb_ffa_send_receive(unsigned long func_id, ret = tpm_crb_ffa_to_linux_errno(tpm_crb_ffa->direct_msg_data.data1); } + return ret; +} + +static int __tpm_crb_ffa_send_receive(unsigned long func_id, unsigned long a0, + unsigned long a1, unsigned long a2) +{ + ktime_t start, stop; + int ret; + + if (!tpm_crb_ffa) + return -ENOENT; + + start = ktime_get(); + stop = ktime_add(start, ms_to_ktime(busy_timeout_ms)); + + for (;;) { + ret = __tpm_crb_ffa_try_send_receive(func_id, a0, a1, a2); + if (ret != -EBUSY) + break; + + usleep_range(50, 100); + if (ktime_after(ktime_get(), stop)) { + dev_warn(&tpm_crb_ffa->ffa_dev->dev, + "Busy retry timed out\n"); + break; + } + } return ret; }