aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Gunthorpe <jgunthorpe@obsidianresearch.com>2017-02-21 16:14:24 -0500
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2017-04-03 15:46:00 -0400
commitb4e2eb0651ac3180a942d378b040c5cc045113ee (patch)
treea1c0dcf430bf20aa9df84594eb2a055d696f968b
parent302a6ad7fc77146191126a1f3e2c5d724fd72416 (diff)
tpm crb: Work around BIOS's that report the wrong ACPI region size
The expectation is that the if the CRB cmd/rsp buffer falls within the ACPI region that the entire buffer will be within the reason. Otherwise resource reservation will fail when it crosses regions. Work around this BIOS bug by limiting the cmd/rsp buffer to the length of the declared ACPI region. BIOS vendors should fix this by making the ACPI and register length declarations consistent. Reported-by: Davide Guerri <davide.guerri@gmail.com> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Davide Guerri <davide.guerri@gmail.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
-rw-r--r--drivers/char/tpm/tpm_crb.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 86f355b6df1d..421dfa959a4f 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -295,6 +295,27 @@ static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv,
295 return priv->iobase + (new_res.start - io_res->start); 295 return priv->iobase + (new_res.start - io_res->start);
296} 296}
297 297
298/*
299 * Work around broken BIOSs that return inconsistent values from the ACPI
300 * region vs the registers. Trust the ACPI region. Such broken systems
301 * probably cannot send large TPM commands since the buffer will be truncated.
302 */
303static u64 crb_fixup_cmd_size(struct device *dev, struct resource *io_res,
304 u64 start, u64 size)
305{
306 if (io_res->start > start || io_res->end < start)
307 return size;
308
309 if (start + size - 1 <= io_res->end)
310 return size;
311
312 dev_err(dev,
313 FW_BUG "ACPI region does not cover the entire command/response buffer. %pr vs %llx %llx\n",
314 io_res, start, size);
315
316 return io_res->end - start + 1;
317}
318
298static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, 319static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
299 struct acpi_table_tpm2 *buf) 320 struct acpi_table_tpm2 *buf)
300{ 321{
@@ -340,7 +361,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
340 pa_high = ioread32(&priv->cca->cmd_pa_high); 361 pa_high = ioread32(&priv->cca->cmd_pa_high);
341 pa_low = ioread32(&priv->cca->cmd_pa_low); 362 pa_low = ioread32(&priv->cca->cmd_pa_low);
342 cmd_pa = ((u64)pa_high << 32) | pa_low; 363 cmd_pa = ((u64)pa_high << 32) | pa_low;
343 cmd_size = ioread32(&priv->cca->cmd_size); 364 cmd_size = crb_fixup_cmd_size(dev, &io_res, cmd_pa,
365 ioread32(&priv->cca->cmd_size));
344 366
345 dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n", 367 dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n",
346 pa_high, pa_low, cmd_size); 368 pa_high, pa_low, cmd_size);
@@ -353,7 +375,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
353 375
354 memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); 376 memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8);
355 rsp_pa = le64_to_cpu(rsp_pa); 377 rsp_pa = le64_to_cpu(rsp_pa);
356 rsp_size = ioread32(&priv->cca->rsp_size); 378 rsp_size = crb_fixup_cmd_size(dev, &io_res, rsp_pa,
379 ioread32(&priv->cca->rsp_size));
357 380
358 if (cmd_pa != rsp_pa) { 381 if (cmd_pa != rsp_pa) {
359 priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); 382 priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size);