* Re: [RFC v2 1/5] tpm_crb: Add register definitions of TPM CRB chunking fields [not found] ` <20260324181244.17741-2-armenon@redhat.com> @ 2026-05-09 14:41 ` Jarkko Sakkinen 0 siblings, 0 replies; 9+ messages in thread From: Jarkko Sakkinen @ 2026-05-09 14:41 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Tue, Mar 24, 2026 at 11:42:40PM +0530, Arun Menon wrote: > Post-quantum cryptographic (PQC) algorithms can require buffer sizes that > exceed the physical capacity of the TPM's Command/Response Buffer (CRB). > To support these larger payloads, the TPM 2.0 CRB specification [1] > allows for data chunking when the physical MMIO window is smaller than > the required buffer size. > > To support this protocol, the TPM driver must be able to detect the > chunking capability, and signal the backend using specific start > method flags, also known as the control area start register bits. > > As per sections 6.4.2.2 and 6.5.3.9 of the specification document [1] > Add 2 new bit flags to the existing enum crb_start and add the > capability bit. > - CRB_INTF_CAP_CRB_CHUNK: A capability bit used to detect if the backend > supports chunking. > - CRB_START_NEXT_CHUNK: A control bit to signal the TPM to consume the > current command buffer, or to get the next chunk from the response > buffer. > - CRB_START_RESP_RETRY: A control bit to signal retransmission of a > response buffer. > > [1] https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p07_rc1_121225.pdf > > Signed-off-by: Arun Menon <armenon@redhat.com> > --- > drivers/char/tpm/tpm_crb.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > index 6c25305c256ef..67c0061d4cab7 100644 > --- a/drivers/char/tpm/tpm_crb.c > +++ b/drivers/char/tpm/tpm_crb.c > @@ -56,12 +56,18 @@ enum crb_ctrl_sts { > > enum crb_start { > CRB_START_INVOKE = BIT(0), > + CRB_START_RESP_RETRY = BIT(1), > + CRB_START_NEXT_CHUNK = BIT(2), > }; > > enum crb_cancel { > CRB_CANCEL_INVOKE = BIT(0), > }; > > +enum crb_intf { > + CRB_INTF_CAP_CRB_CHUNK = BIT(10), > +}; > + > struct crb_regs_head { > u32 loc_state; > u32 reserved1; > -- > 2.53.0 > Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> BR, Jarkko ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <20260324181244.17741-3-armenon@redhat.com>]
* Re: [RFC v2 2/5] tpm_crb: Add new wrapper function to invoke start method [not found] ` <20260324181244.17741-3-armenon@redhat.com> @ 2026-05-09 14:43 ` Jarkko Sakkinen 2026-05-13 11:08 ` Arun Menon 0 siblings, 1 reply; 9+ messages in thread From: Jarkko Sakkinen @ 2026-05-09 14:43 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Tue, Mar 24, 2026 at 11:42:41PM +0530, Arun Menon wrote: > The current implementation handles different platform start methods > (ACPI, ARM SMC, and ARM FFA) directly within crb_send(), but it is > limited to triggering the CRB_START_INVOKE bit. > > To support cmd/rsp chunking, the driver must be able to send other > control bits, like CRB_START_NEXT_CHUNK, using these same > platform-specific paths. > > By moving this logic into a new helper function, crb_trigger_tpm(), > the driver can now send any required control bit across all supported > platforms. This prepares the driver for the upcoming chunking support. > > No functional change is intended. > > Signed-off-by: Arun Menon <armenon@redhat.com> > --- > drivers/char/tpm/tpm_crb.c | 50 ++++++++++++++++++++------------------ > 1 file changed, 27 insertions(+), 23 deletions(-) > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > index 67c0061d4cab7..922bcf7a69ad5 100644 > --- a/drivers/char/tpm/tpm_crb.c > +++ b/drivers/char/tpm/tpm_crb.c > @@ -445,6 +445,32 @@ static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) > } > #endif > > +static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) tpm_crb_start? I'd also split this into two commits: 1. One that splits the helper. 2. Second that adds the new stuff. > +{ > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > + int rc = 0; > + /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > + * report only ACPI start but in practice seems to require both > + * CRB start, hence invoking CRB start method if hid == MSFT0101. > + */ > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > + priv->sm == ACPI_TPM2_MEMORY_MAPPED || > + !strcmp(priv->hid, "MSFT0101")) > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > + if (priv->sm == ACPI_TPM2_START_METHOD || > + priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > + rc = crb_do_acpi_start(chip); > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > + rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > + } > + if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > + rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > + } > + return rc; > +} > + > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > { > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > @@ -470,29 +496,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > /* Make sure that cmd is populated before issuing start. */ > wmb(); > > - /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > - * report only ACPI start but in practice seems to require both > - * CRB start, hence invoking CRB start method if hid == MSFT0101. > - */ > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > - priv->sm == ACPI_TPM2_MEMORY_MAPPED || > - !strcmp(priv->hid, "MSFT0101")) > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > - > - if (priv->sm == ACPI_TPM2_START_METHOD || > - priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > - rc = crb_do_acpi_start(chip); > - > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > - rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > - } > - > - if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > - rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > - } > - > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > if (rc) > return rc; > > -- > 2.53.0 > BR, Jarkko ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC v2 2/5] tpm_crb: Add new wrapper function to invoke start method 2026-05-09 14:43 ` [RFC v2 2/5] tpm_crb: Add new wrapper function to invoke start method Jarkko Sakkinen @ 2026-05-13 11:08 ` Arun Menon 0 siblings, 0 replies; 9+ messages in thread From: Arun Menon @ 2026-05-13 11:08 UTC (permalink / raw) To: Jarkko Sakkinen Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Sat, May 09, 2026 at 05:43:10PM +0300, Jarkko Sakkinen wrote: > On Tue, Mar 24, 2026 at 11:42:41PM +0530, Arun Menon wrote: > > The current implementation handles different platform start methods > > (ACPI, ARM SMC, and ARM FFA) directly within crb_send(), but it is > > limited to triggering the CRB_START_INVOKE bit. > > > > To support cmd/rsp chunking, the driver must be able to send other > > control bits, like CRB_START_NEXT_CHUNK, using these same > > platform-specific paths. > > > > By moving this logic into a new helper function, crb_trigger_tpm(), > > the driver can now send any required control bit across all supported > > platforms. This prepares the driver for the upcoming chunking support. > > > > No functional change is intended. > > > > Signed-off-by: Arun Menon <armenon@redhat.com> > > --- > > drivers/char/tpm/tpm_crb.c | 50 ++++++++++++++++++++------------------ > > 1 file changed, 27 insertions(+), 23 deletions(-) > > > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > > index 67c0061d4cab7..922bcf7a69ad5 100644 > > --- a/drivers/char/tpm/tpm_crb.c > > +++ b/drivers/char/tpm/tpm_crb.c > > @@ -445,6 +445,32 @@ static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) > > } > > #endif > > > > +static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) > > tpm_crb_start? Yes, it can be renamed. On the qemu side also, its renamed and made consistent with the spec. > > I'd also split this into two commits: > > 1. One that splits the helper. > 2. Second that adds the new stuff. Yes. Will do. Thank you. > > > +{ > > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > + int rc = 0; > > + /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > > + * report only ACPI start but in practice seems to require both > > + * CRB start, hence invoking CRB start method if hid == MSFT0101. > > + */ > > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > > + priv->sm == ACPI_TPM2_MEMORY_MAPPED || > > + !strcmp(priv->hid, "MSFT0101")) > > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > > + if (priv->sm == ACPI_TPM2_START_METHOD || > > + priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > > + rc = crb_do_acpi_start(chip); > > + if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > > + rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > > + } > > + if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > > + iowrite32(start_cmd, &priv->regs_t->ctrl_start); > > + rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > > + } > > + return rc; > > +} > > + > > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > { > > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > @@ -470,29 +496,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > /* Make sure that cmd is populated before issuing start. */ > > wmb(); > > > > - /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs > > - * report only ACPI start but in practice seems to require both > > - * CRB start, hence invoking CRB start method if hid == MSFT0101. > > - */ > > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER || > > - priv->sm == ACPI_TPM2_MEMORY_MAPPED || > > - !strcmp(priv->hid, "MSFT0101")) > > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > > - > > - if (priv->sm == ACPI_TPM2_START_METHOD || > > - priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) > > - rc = crb_do_acpi_start(chip); > > - > > - if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) { > > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > > - rc = tpm_crb_smc_start(&chip->dev, priv->smc_func_id); > > - } > > - > > - if (priv->sm == ACPI_TPM2_CRB_WITH_ARM_FFA) { > > - iowrite32(CRB_START_INVOKE, &priv->regs_t->ctrl_start); > > - rc = tpm_crb_ffa_start(CRB_FFA_START_TYPE_COMMAND, chip->locality); > > - } > > - > > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > > if (rc) > > return rc; > > > > -- > > 2.53.0 > > > > BR, Jarkko > Regards, Arun Menon ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <20260324181244.17741-4-armenon@redhat.com>]
* Re: [RFC v2 3/5] tpm_crb: Implement command and response chunking logic [not found] ` <20260324181244.17741-4-armenon@redhat.com> @ 2026-05-09 14:53 ` Jarkko Sakkinen 2026-05-13 11:07 ` Arun Menon 0 siblings, 1 reply; 9+ messages in thread From: Jarkko Sakkinen @ 2026-05-09 14:53 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Tue, Mar 24, 2026 at 11:42:42PM +0530, Arun Menon wrote: > With the introduction of support for Post Quantum Cryptography > algorithms in TPM, the commands and responses will grow in size. > Some TPMs have a physical hardware memory window (MMIO) that is > smaller than the commands we need to send. Therefore this commit > implements the core logic of sending/receiving data in chunks. > > Instead of sending the whole command at once, the driver now sends it in > small chunks. After each chunk, it signals the TPM using a nextChunk > signal, and waits for the TPM to consume the data. Once the final piece > is delivered, the driver signals the TPM to begin execution by toggling > the start invoke bit. We use the same logic in reverse to read large > responses from the TPM. > > This allows the driver to handle large payloads even when the hardware > interface has limited memory. This kernel-side support corresponds to > the backend implementation in QEMU [1]. QEMU reassembles the chunks > before passing them to the TPM emulator. > > [1] https://lore.kernel.org/qemu-devel/20260319135316.37412-1-armenon@redhat.com/ > > Signed-off-by: Arun Menon <armenon@redhat.com> > --- This is really bad at rationalizing the code change, which are heavy. Couldn't you instead: 1. Rename crb_recv as tpm_crb_recv_no_chunks(). 2. Add tpm_crb_recv_chunks(). 3. Add new tpm_crb_recv(), which delegates either. I would not mind too much if they have some duplicate logic. It's less of a harm than convolution caused by interleaving. > drivers/char/tpm/tpm_crb.c | 155 +++++++++++++++++++++++++++---------- > 1 file changed, 114 insertions(+), 41 deletions(-) > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > index 922bcf7a69ad5..a97fc5e9927e3 100644 > --- a/drivers/char/tpm/tpm_crb.c > +++ b/drivers/char/tpm/tpm_crb.c > @@ -104,11 +104,13 @@ struct crb_priv { > u8 __iomem *cmd; > u8 __iomem *rsp; > u32 cmd_size; > + u32 rsp_size; > u32 smc_func_id; > u32 __iomem *pluton_start_addr; > u32 __iomem *pluton_reply_addr; > u8 ffa_flags; > u8 ffa_attributes; > + bool chunking_supported; Why not "u32 intf_id" i.e. cache the value of the register? > }; > > struct tpm2_crb_smc { > @@ -368,38 +370,6 @@ static u8 crb_status(struct tpm_chip *chip) > return sts; > } > > -static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > -{ > - struct crb_priv *priv = dev_get_drvdata(&chip->dev); > - unsigned int expected; > - > - /* A sanity check that the upper layer wants to get at least the header > - * as that is the minimum size for any TPM response. > - */ > - if (count < TPM_HEADER_SIZE) > - return -EIO; > - > - /* If this bit is set, according to the spec, the TPM is in > - * unrecoverable condition. > - */ > - if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > - return -EIO; > - > - /* Read the first 8 bytes in order to get the length of the response. > - * We read exactly a quad word in order to make sure that the remaining > - * reads will be aligned. > - */ > - memcpy_fromio(buf, priv->rsp, 8); > - > - expected = be32_to_cpup((__be32 *)&buf[2]); > - if (expected > count || expected < TPM_HEADER_SIZE) > - return -EIO; > - > - memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8); > - > - return expected; > -} > - > static int crb_do_acpi_start(struct tpm_chip *chip) > { > union acpi_object *obj; > @@ -474,6 +444,8 @@ static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > { > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > + size_t offset = 0; > + size_t chunk_size; > int rc = 0; > > /* Zero the cancel register so that the next command will not get > @@ -481,7 +453,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > */ > iowrite32(0, &priv->regs_t->ctrl_cancel); > > - if (len > priv->cmd_size) { > + if (len > priv->cmd_size && !priv->chunking_supported) { > dev_err(&chip->dev, "invalid command count value %zd %d\n", > len, priv->cmd_size); > return -E2BIG; > @@ -491,18 +463,108 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) > __crb_cmd_ready(&chip->dev, priv, chip->locality); > > - memcpy_toio(priv->cmd, buf, len); > + while (offset < len) { > + chunk_size = min_t(size_t, len - offset, priv->cmd_size); > > - /* Make sure that cmd is populated before issuing start. */ > - wmb(); > - > - rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > - if (rc) > - return rc; > + if (chunk_size == 0) > + break; > > + memcpy_toio(priv->cmd, buf + offset, chunk_size); > + offset += chunk_size; > + > + /* Make sure that cmd is populated before issuing start. */ > + wmb(); > + if (offset < len) { > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > + if (rc) > + return rc; > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > + dev_err(&chip->dev, > + "Timeout waiting for backend to consume chunk\n"); > + return -ETIME; > + } > + } else { > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > + if (rc) > + return rc; > + } > + } > return crb_try_pluton_doorbell(priv, false); > } > > +static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > +{ > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > + unsigned int expected; > + size_t offset = 0; > + size_t chunk_size; > + size_t first_read; > + int rc; > + > + /* A sanity check that the upper layer wants to get at least the header > + * as that is the minimum size for any TPM response. > + */ > + if (count < TPM_HEADER_SIZE) > + return -EIO; > + > + /* If this bit is set, according to the spec, the TPM is in > + * unrecoverable condition. > + */ > + if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > + return -EIO; > + > + /* Read the first 8 bytes in order to get the length of the response. > + * We read exactly a quad word in order to make sure that the remaining > + * reads will be aligned. > + */ > + memcpy_fromio(buf, priv->rsp, 8); > + > + expected = be32_to_cpup((__be32 *)&buf[2]); > + if (expected > count || expected < TPM_HEADER_SIZE) > + return -EIO; > + > + /* > + * Set chunk_size by comparing the size of the buffer that the upper layer has > + * allocated (count) to the hardware tpm limit (priv->rsp_size). > + * This is to prevent buffer overflow while writing to buf. > + */ > + chunk_size = min_t(size_t, count, priv->rsp_size); > + if (chunk_size < 8) > + return -EIO; > + > + /* > + * Compare the actual size of the response we found in the header to the chunk_size. > + */ > + first_read = min_t(size_t, expected, chunk_size); > + > + memcpy_fromio(&buf[8], &priv->rsp[8], first_read - 8); > + offset = first_read; > + > + while (offset < expected) { > + if (!priv->chunking_supported) { > + dev_err(&chip->dev, "Response larger than MMIO and chunking not supported\n"); > + return -EIO; > + } > + > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > + if (rc) > + return rc; > + > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > + dev_err(&chip->dev, "Timeout waiting for backend response\n"); > + return -ETIME; > + } > + > + chunk_size = min_t(size_t, expected - offset, priv->rsp_size); > + memcpy_fromio(buf + offset, priv->rsp, chunk_size); > + offset += chunk_size; > + } > + > + return expected; > +} > + > static void crb_cancel(struct tpm_chip *chip) > { > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > @@ -727,6 +789,15 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > goto out; > } > > + if (priv->regs_h) { > + u32 intf_id = ioread32((u32 __iomem *)&priv->regs_h->intf_id); > + > + if (intf_id & CRB_INTF_CAP_CRB_CHUNK) { > + priv->chunking_supported = true; > + dev_info(dev, "CRB Chunking is supported by backend\n"); > + } > + } > + > memcpy_fromio(&__rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); > rsp_pa = le64_to_cpu(__rsp_pa); > rsp_size = ioread32(&priv->regs_t->ctrl_rsp_size); > @@ -764,8 +835,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > priv->rsp = priv->cmd; > > out: > - if (!ret) > + if (!ret) { > priv->cmd_size = cmd_size; > + priv->rsp_size = rsp_size; > + } > > __crb_go_idle(dev, priv, 0); > > -- > 2.53.0 > BR, Jarkko ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC v2 3/5] tpm_crb: Implement command and response chunking logic 2026-05-09 14:53 ` [RFC v2 3/5] tpm_crb: Implement command and response chunking logic Jarkko Sakkinen @ 2026-05-13 11:07 ` Arun Menon 0 siblings, 0 replies; 9+ messages in thread From: Arun Menon @ 2026-05-13 11:07 UTC (permalink / raw) To: Jarkko Sakkinen Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Sat, May 09, 2026 at 05:53:51PM +0300, Jarkko Sakkinen wrote: > On Tue, Mar 24, 2026 at 11:42:42PM +0530, Arun Menon wrote: > > With the introduction of support for Post Quantum Cryptography > > algorithms in TPM, the commands and responses will grow in size. > > Some TPMs have a physical hardware memory window (MMIO) that is > > smaller than the commands we need to send. Therefore this commit > > implements the core logic of sending/receiving data in chunks. > > > > Instead of sending the whole command at once, the driver now sends it in > > small chunks. After each chunk, it signals the TPM using a nextChunk > > signal, and waits for the TPM to consume the data. Once the final piece > > is delivered, the driver signals the TPM to begin execution by toggling > > the start invoke bit. We use the same logic in reverse to read large > > responses from the TPM. > > > > This allows the driver to handle large payloads even when the hardware > > interface has limited memory. This kernel-side support corresponds to > > the backend implementation in QEMU [1]. QEMU reassembles the chunks > > before passing them to the TPM emulator. > > > > [1] https://lore.kernel.org/qemu-devel/20260319135316.37412-1-armenon@redhat.com/ > > > > Signed-off-by: Arun Menon <armenon@redhat.com> > > --- > > This is really bad at rationalizing the code change, which are heavy. > > Couldn't you instead: > > 1. Rename crb_recv as tpm_crb_recv_no_chunks(). > 2. Add tpm_crb_recv_chunks(). > 3. Add new tpm_crb_recv(), which delegates either. > > I would not mind too much if they have some duplicate logic. It's less > of a harm than convolution caused by interleaving. Sure. I will amend this in v3. Thank you. > > > drivers/char/tpm/tpm_crb.c | 155 +++++++++++++++++++++++++++---------- > > 1 file changed, 114 insertions(+), 41 deletions(-) > > > > diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c > > index 922bcf7a69ad5..a97fc5e9927e3 100644 > > --- a/drivers/char/tpm/tpm_crb.c > > +++ b/drivers/char/tpm/tpm_crb.c > > @@ -104,11 +104,13 @@ struct crb_priv { > > u8 __iomem *cmd; > > u8 __iomem *rsp; > > u32 cmd_size; > > + u32 rsp_size; > > u32 smc_func_id; > > u32 __iomem *pluton_start_addr; > > u32 __iomem *pluton_reply_addr; > > u8 ffa_flags; > > u8 ffa_attributes; > > + bool chunking_supported; > > Why not "u32 intf_id" i.e. cache the value of the register? > > > }; > > > > struct tpm2_crb_smc { > > @@ -368,38 +370,6 @@ static u8 crb_status(struct tpm_chip *chip) > > return sts; > > } > > > > -static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > > -{ > > - struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > - unsigned int expected; > > - > > - /* A sanity check that the upper layer wants to get at least the header > > - * as that is the minimum size for any TPM response. > > - */ > > - if (count < TPM_HEADER_SIZE) > > - return -EIO; > > - > > - /* If this bit is set, according to the spec, the TPM is in > > - * unrecoverable condition. > > - */ > > - if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > > - return -EIO; > > - > > - /* Read the first 8 bytes in order to get the length of the response. > > - * We read exactly a quad word in order to make sure that the remaining > > - * reads will be aligned. > > - */ > > - memcpy_fromio(buf, priv->rsp, 8); > > - > > - expected = be32_to_cpup((__be32 *)&buf[2]); > > - if (expected > count || expected < TPM_HEADER_SIZE) > > - return -EIO; > > - > > - memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8); > > - > > - return expected; > > -} > > - > > static int crb_do_acpi_start(struct tpm_chip *chip) > > { > > union acpi_object *obj; > > @@ -474,6 +444,8 @@ static int crb_trigger_tpm(struct tpm_chip *chip, u32 start_cmd) > > static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > { > > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > + size_t offset = 0; > > + size_t chunk_size; > > int rc = 0; > > > > /* Zero the cancel register so that the next command will not get > > @@ -481,7 +453,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > */ > > iowrite32(0, &priv->regs_t->ctrl_cancel); > > > > - if (len > priv->cmd_size) { > > + if (len > priv->cmd_size && !priv->chunking_supported) { > > dev_err(&chip->dev, "invalid command count value %zd %d\n", > > len, priv->cmd_size); > > return -E2BIG; > > @@ -491,18 +463,108 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz, size_t len) > > if (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) > > __crb_cmd_ready(&chip->dev, priv, chip->locality); > > > > - memcpy_toio(priv->cmd, buf, len); > > + while (offset < len) { > > + chunk_size = min_t(size_t, len - offset, priv->cmd_size); > > > > - /* Make sure that cmd is populated before issuing start. */ > > - wmb(); > > - > > - rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > > - if (rc) > > - return rc; > > + if (chunk_size == 0) > > + break; > > > > + memcpy_toio(priv->cmd, buf + offset, chunk_size); > > + offset += chunk_size; > > + > > + /* Make sure that cmd is populated before issuing start. */ > > + wmb(); > > + if (offset < len) { > > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > > + if (rc) > > + return rc; > > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > > + dev_err(&chip->dev, > > + "Timeout waiting for backend to consume chunk\n"); > > + return -ETIME; > > + } > > + } else { > > + rc = crb_trigger_tpm(chip, CRB_START_INVOKE); > > + if (rc) > > + return rc; > > + } > > + } > > return crb_try_pluton_doorbell(priv, false); > > } > > > > +static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) > > +{ > > + struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > + unsigned int expected; > > + size_t offset = 0; > > + size_t chunk_size; > > + size_t first_read; > > + int rc; > > + > > + /* A sanity check that the upper layer wants to get at least the header > > + * as that is the minimum size for any TPM response. > > + */ > > + if (count < TPM_HEADER_SIZE) > > + return -EIO; > > + > > + /* If this bit is set, according to the spec, the TPM is in > > + * unrecoverable condition. > > + */ > > + if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) > > + return -EIO; > > + > > + /* Read the first 8 bytes in order to get the length of the response. > > + * We read exactly a quad word in order to make sure that the remaining > > + * reads will be aligned. > > + */ > > + memcpy_fromio(buf, priv->rsp, 8); > > + > > + expected = be32_to_cpup((__be32 *)&buf[2]); > > + if (expected > count || expected < TPM_HEADER_SIZE) > > + return -EIO; > > + > > + /* > > + * Set chunk_size by comparing the size of the buffer that the upper layer has > > + * allocated (count) to the hardware tpm limit (priv->rsp_size). > > + * This is to prevent buffer overflow while writing to buf. > > + */ > > + chunk_size = min_t(size_t, count, priv->rsp_size); > > + if (chunk_size < 8) > > + return -EIO; > > + > > + /* > > + * Compare the actual size of the response we found in the header to the chunk_size. > > + */ > > + first_read = min_t(size_t, expected, chunk_size); > > + > > + memcpy_fromio(&buf[8], &priv->rsp[8], first_read - 8); > > + offset = first_read; > > + > > + while (offset < expected) { > > + if (!priv->chunking_supported) { > > + dev_err(&chip->dev, "Response larger than MMIO and chunking not supported\n"); > > + return -EIO; > > + } > > + > > + rc = crb_trigger_tpm(chip, CRB_START_NEXT_CHUNK); > > + if (rc) > > + return rc; > > + > > + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_start, > > + CRB_START_NEXT_CHUNK, 0, TPM2_TIMEOUT_C)) { > > + dev_err(&chip->dev, "Timeout waiting for backend response\n"); > > + return -ETIME; > > + } > > + > > + chunk_size = min_t(size_t, expected - offset, priv->rsp_size); > > + memcpy_fromio(buf + offset, priv->rsp, chunk_size); > > + offset += chunk_size; > > + } > > + > > + return expected; > > +} > > + > > static void crb_cancel(struct tpm_chip *chip) > > { > > struct crb_priv *priv = dev_get_drvdata(&chip->dev); > > @@ -727,6 +789,15 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > > goto out; > > } > > > > + if (priv->regs_h) { > > + u32 intf_id = ioread32((u32 __iomem *)&priv->regs_h->intf_id); > > + > > + if (intf_id & CRB_INTF_CAP_CRB_CHUNK) { > > + priv->chunking_supported = true; > > + dev_info(dev, "CRB Chunking is supported by backend\n"); > > + } > > + } > > + > > memcpy_fromio(&__rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); > > rsp_pa = le64_to_cpu(__rsp_pa); > > rsp_size = ioread32(&priv->regs_t->ctrl_rsp_size); > > @@ -764,8 +835,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, > > priv->rsp = priv->cmd; > > > > out: > > - if (!ret) > > + if (!ret) { > > priv->cmd_size = cmd_size; > > + priv->rsp_size = rsp_size; > > + } > > > > __crb_go_idle(dev, priv, 0); > > > > -- > > 2.53.0 > > > > BR, Jarkko > Regards, Arun Menon ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <20260324181244.17741-5-armenon@redhat.com>]
* Re: [RFC v2 4/5] tpm: Increase TPM_BUFSIZE to 8kB for chunking support [not found] ` <20260324181244.17741-5-armenon@redhat.com> @ 2026-05-09 14:54 ` Jarkko Sakkinen 2026-05-09 15:07 ` Jarkko Sakkinen 2026-05-13 11:09 ` Arun Menon 0 siblings, 2 replies; 9+ messages in thread From: Jarkko Sakkinen @ 2026-05-09 14:54 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Tue, Mar 24, 2026 at 11:42:43PM +0530, Arun Menon wrote: > The size of the command is checked against TPM_BUFSIZE early on before > even sending it to the backend. We therefore need to increase the > TPM_BUFSIZE to allow support for larger commands. > > For now, 8KB seems sufficient for ML-KEM and ML-DSA algorithms and it is > also order-1 safe. > > Signed-off-by: Arun Menon <armenon@redhat.com> > --- > drivers/char/tpm/tpm.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > index 87d68ddf270a7..26c3765fbd732 100644 > --- a/drivers/char/tpm/tpm.h > +++ b/drivers/char/tpm/tpm.h > @@ -33,7 +33,7 @@ > #endif > > #define TPM_MINOR 224 /* officially assigned */ > -#define TPM_BUFSIZE 4096 > +#define TPM_BUFSIZE 8192 > #define TPM_NUM_DEVICES 65536 > #define TPM_RETRY 50 > > -- > 2.53.0 > Shouldn't this prepend previous patch? BR, Jarkko ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC v2 4/5] tpm: Increase TPM_BUFSIZE to 8kB for chunking support 2026-05-09 14:54 ` [RFC v2 4/5] tpm: Increase TPM_BUFSIZE to 8kB for chunking support Jarkko Sakkinen @ 2026-05-09 15:07 ` Jarkko Sakkinen 2026-05-13 11:06 ` Arun Menon 2026-05-13 11:09 ` Arun Menon 1 sibling, 1 reply; 9+ messages in thread From: Jarkko Sakkinen @ 2026-05-09 15:07 UTC (permalink / raw) To: Arun Menon; +Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Sat, May 09, 2026 at 05:54:25PM +0300, Jarkko Sakkinen wrote: > On Tue, Mar 24, 2026 at 11:42:43PM +0530, Arun Menon wrote: > > The size of the command is checked against TPM_BUFSIZE early on before > > even sending it to the backend. We therefore need to increase the > > TPM_BUFSIZE to allow support for larger commands. > > > > For now, 8KB seems sufficient for ML-KEM and ML-DSA algorithms and it is > > also order-1 safe. > > > > Signed-off-by: Arun Menon <armenon@redhat.com> > > --- > > drivers/char/tpm/tpm.h | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > > index 87d68ddf270a7..26c3765fbd732 100644 > > --- a/drivers/char/tpm/tpm.h > > +++ b/drivers/char/tpm/tpm.h > > @@ -33,7 +33,7 @@ > > #endif > > > > #define TPM_MINOR 224 /* officially assigned */ > > -#define TPM_BUFSIZE 4096 > > +#define TPM_BUFSIZE 8192 > > #define TPM_NUM_DEVICES 65536 > > #define TPM_RETRY 50 > > > > -- > > 2.53.0 > > > > Shouldn't this prepend previous patch? Also did you remark that tpm_buf would also need changes as it is fixed to PAGE_SIZE? I've made a patch that essentially makes tpm_buf size variable as caller does kzalloc: https://lore.kernel.org/linux-integrity/20260125192526.782202-12-jarkko@kernel.org/ I'd see this as pretty good long-term solution. BR, Jarkko ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC v2 4/5] tpm: Increase TPM_BUFSIZE to 8kB for chunking support 2026-05-09 15:07 ` Jarkko Sakkinen @ 2026-05-13 11:06 ` Arun Menon 0 siblings, 0 replies; 9+ messages in thread From: Arun Menon @ 2026-05-13 11:06 UTC (permalink / raw) To: Jarkko Sakkinen Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Sat, May 09, 2026 at 06:07:11PM +0300, Jarkko Sakkinen wrote: > On Sat, May 09, 2026 at 05:54:25PM +0300, Jarkko Sakkinen wrote: > > On Tue, Mar 24, 2026 at 11:42:43PM +0530, Arun Menon wrote: > > > The size of the command is checked against TPM_BUFSIZE early on before > > > even sending it to the backend. We therefore need to increase the > > > TPM_BUFSIZE to allow support for larger commands. > > > > > > For now, 8KB seems sufficient for ML-KEM and ML-DSA algorithms and it is > > > also order-1 safe. > > > > > > Signed-off-by: Arun Menon <armenon@redhat.com> > > > --- > > > drivers/char/tpm/tpm.h | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > > > index 87d68ddf270a7..26c3765fbd732 100644 > > > --- a/drivers/char/tpm/tpm.h > > > +++ b/drivers/char/tpm/tpm.h > > > @@ -33,7 +33,7 @@ > > > #endif > > > > > > #define TPM_MINOR 224 /* officially assigned */ > > > -#define TPM_BUFSIZE 4096 > > > +#define TPM_BUFSIZE 8192 > > > #define TPM_NUM_DEVICES 65536 > > > #define TPM_RETRY 50 > > > > > > -- > > > 2.53.0 > > > > > > > Shouldn't this prepend previous patch? > > Also did you remark that tpm_buf would also need changes as it is fixed > to PAGE_SIZE? TPM_BUFSIZE can be increased, in its new location include/linux/tpm.h as per the patch : https://lore.kernel.org/linux-integrity/20260125192526.782202-12-jarkko@kernel.org/ and I think that alone will take care of the check if (size > TPM_BUFSIZE) in tpm_common_write() in drivers/char/tpm/tpm-dev-common.c. However I was not able to apply the mbox file cleanly on the existing branches for-next-tpm and for-next-keys. I could apply them cleanly on the old branch (next). Please guide. I would only change the TPM_BUFSIZE set in [PATCH v9 11/11] tpm-buf: Implement managed allocations to 8192. > > I've made a patch that essentially makes tpm_buf size variable as caller > does kzalloc: > > https://lore.kernel.org/linux-integrity/20260125192526.782202-12-jarkko@kernel.org/ > > I'd see this as pretty good long-term solution. Indeed. > > BR, Jarkko > Regards, Arun Menon ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC v2 4/5] tpm: Increase TPM_BUFSIZE to 8kB for chunking support 2026-05-09 14:54 ` [RFC v2 4/5] tpm: Increase TPM_BUFSIZE to 8kB for chunking support Jarkko Sakkinen 2026-05-09 15:07 ` Jarkko Sakkinen @ 2026-05-13 11:09 ` Arun Menon 1 sibling, 0 replies; 9+ messages in thread From: Arun Menon @ 2026-05-13 11:09 UTC (permalink / raw) To: Jarkko Sakkinen Cc: linux-kernel, linux-integrity, Peter Huewe, Jason Gunthorpe On Sat, May 09, 2026 at 05:54:21PM +0300, Jarkko Sakkinen wrote: > On Tue, Mar 24, 2026 at 11:42:43PM +0530, Arun Menon wrote: > > The size of the command is checked against TPM_BUFSIZE early on before > > even sending it to the backend. We therefore need to increase the > > TPM_BUFSIZE to allow support for larger commands. > > > > For now, 8KB seems sufficient for ML-KEM and ML-DSA algorithms and it is > > also order-1 safe. > > > > Signed-off-by: Arun Menon <armenon@redhat.com> > > --- > > drivers/char/tpm/tpm.h | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > > index 87d68ddf270a7..26c3765fbd732 100644 > > --- a/drivers/char/tpm/tpm.h > > +++ b/drivers/char/tpm/tpm.h > > @@ -33,7 +33,7 @@ > > #endif > > > > #define TPM_MINOR 224 /* officially assigned */ > > -#define TPM_BUFSIZE 4096 > > +#define TPM_BUFSIZE 8192 > > #define TPM_NUM_DEVICES 65536 > > #define TPM_RETRY 50 > > > > -- > > 2.53.0 > > > > Shouldn't this prepend previous patch? yes, I am going to put this and the i2c patch before the chunking logic. Thanks. > > BR, Jarkko > Regards, Arun Menon ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-05-13 11:09 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260324181244.17741-1-armenon@redhat.com>
[not found] ` <20260324181244.17741-2-armenon@redhat.com>
2026-05-09 14:41 ` [RFC v2 1/5] tpm_crb: Add register definitions of TPM CRB chunking fields Jarkko Sakkinen
[not found] ` <20260324181244.17741-3-armenon@redhat.com>
2026-05-09 14:43 ` [RFC v2 2/5] tpm_crb: Add new wrapper function to invoke start method Jarkko Sakkinen
2026-05-13 11:08 ` Arun Menon
[not found] ` <20260324181244.17741-4-armenon@redhat.com>
2026-05-09 14:53 ` [RFC v2 3/5] tpm_crb: Implement command and response chunking logic Jarkko Sakkinen
2026-05-13 11:07 ` Arun Menon
[not found] ` <20260324181244.17741-5-armenon@redhat.com>
2026-05-09 14:54 ` [RFC v2 4/5] tpm: Increase TPM_BUFSIZE to 8kB for chunking support Jarkko Sakkinen
2026-05-09 15:07 ` Jarkko Sakkinen
2026-05-13 11:06 ` Arun Menon
2026-05-13 11:09 ` Arun Menon
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox