Skip to content

Commit ca82895

Browse files
Luigi SemenzatoChromeBot
authored andcommitted
CHROMIUM: workaround for Infineon TPM defensive timeout (v2)
The SLB9635 TPM by Infineon goes into a self-defense mode when power is cut in the middle of a command too many times, and getting it out of that mode is difficult and takes a long time. This patch adds a shutdown-time callback that grabs the mutex wrapping a request-response transaction, so it's less likely that we'll lose power in the middle of a command. Note that the TPM may lose power also across suspend/resume (depending on hardware). However, the suspend callback sends a SaveState command, which can only be sent when other running commands have completed. I am not sure if a command can start after the suspend callback has completed (I doubt it) but even if it does, it will be a sufficiently rare event, and the self-defense can tolerate that. The "gentle shutdown" message is added to make it easier to detect if we neglect to carry this patch forward. BUG=chromium:234796 TEST=extensively tested with the librarian simulator Signed-off-by: Luigi Semenzato <[email protected]> Change-Id: I1bb0a6d574c96a33f4344d47e3e7584e3f67fb14 Reviewed-on: https://gerrit.chromium.org/gerrit/58902 Tested-by: Luigi Semenzato <[email protected]> Reviewed-by: Darren Krahn <[email protected]> Commit-Queue: Luigi Semenzato <[email protected]> Reviewed-by: Olof Johansson <[email protected]>
1 parent 06322c6 commit ca82895

File tree

3 files changed

+22
-1
lines changed

3 files changed

+22
-1
lines changed

drivers/char/tpm/tpm.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/mutex.h>
3030
#include <linux/spinlock.h>
3131
#include <linux/freezer.h>
32+
#include <linux/reboot.h>
3233

3334
#include "tpm.h"
3435
#include "tpm_eventlog.h"
@@ -1465,10 +1466,22 @@ static void tpm_dev_release(struct device *dev)
14651466
tpm_dev_vendor_release(chip);
14661467

14671468
chip->release(dev);
1469+
unregister_reboot_notifier(&chip->shutdown_nb);
14681470
kfree(chip);
14691471
}
14701472
EXPORT_SYMBOL_GPL(tpm_dev_release);
14711473

1474+
static int tpm_shutdown_notify(struct notifier_block *nb,
1475+
unsigned long unused, void *unused2)
1476+
{
1477+
struct tpm_chip *chip = container_of(nb, struct tpm_chip, shutdown_nb);
1478+
dev_dbg(chip->dev, "acquiring shutdown lock\n");
1479+
mutex_lock(&chip->tpm_mutex);
1480+
dev_dbg(chip->dev, "acquired shutdown lock\n");
1481+
return NOTIFY_DONE;
1482+
}
1483+
1484+
14721485
/*
14731486
* Called from tpm_<specific>.c probe function only for devices
14741487
* the driver has determined it should claim. Prior to calling
@@ -1549,6 +1562,13 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
15491562
list_add_rcu(&chip->list, &tpm_chip_list);
15501563
spin_unlock(&driver_lock);
15511564

1565+
/* INFINEON TPM WORKAROUND: Register shutdown callback that ensures we
1566+
* don't shut down in the middle of a TPM command, or we may trigger
1567+
* nasty defensive timeouts at the next boot.
1568+
*/
1569+
chip->shutdown_nb.notifier_call = tpm_shutdown_notify;
1570+
register_reboot_notifier(&chip->shutdown_nb);
1571+
15521572
return chip;
15531573

15541574
put_device:

drivers/char/tpm/tpm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct tpm_chip {
133133

134134
struct list_head list;
135135
void (*release) (struct device *);
136+
struct notifier_block shutdown_nb;
136137
};
137138

138139
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)

drivers/char/tpm/tpm_tis.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
536536
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
537537

538538
dev_info(dev,
539-
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
539+
"1.2 TPM (device-id 0x%X, rev-id %d) [gentle shutdown]\n",
540540
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
541541

542542
if (!itpm) {

0 commit comments

Comments
 (0)