Hopefully this explanation will provide any missing bits of information.
Please correct me where needed.
The Chromebooks use coreboot + payload as firmware. The three payloads of
interest are:
1. Depthcharge. Used when a ChromeOS user boots the machine. Since the
kernel must be signed, presumably the TPM chip is used extensively.
Signing prevents usage with other distributions.
2. The stock version of SeaBIOS. Used in "developer" mode, and provides
typical BIOS functionality. Kernel signature is not checked, so those
parts of the TPM are not needed. However, the machine will reboot on
resume unless the tpm_tis module is loaded and working, as documented
in commit f7595464.
3. A custom version of SeaBIOS. While it could be bespoke, usually it is
built by someone else for all users of a given Chromebook model (see
https://johnlewis.ie/custom-chromebook-firmware/rom-download/ ). It
functions like stock SeaBIOS, except that the TPM usually isn't started
by this payload. However, the ACPI DSDT still has a TPM entry listing
the IFX0102 chip, which causes the tpm_tis module to load. The
tpm_tis_init function calls tpm_get_timeouts, which in turn sees that
the chip has not been started and therefore issues a startup(clear)
command. Now the chip is running. It will not be reboot on resume
(unlike stock SeaBIOS), presumably since the firmware is not
interacting with the TPM. But because an error 38 is returned during
the selftest issued on resume, its functioning will degrade over
suspend/resume cycles until the machine refuses to enter suspend,
Manual workarounds for these three payloads:
1. Depthcharge. I don't know how ChromeOS interacts with the TPM chip.
From what I've seen, it may boot with kernel parameters tpm_tis.force=1
and tpm_tis.interrupts=0 (see #2 following). The kernel is older.
2. Stock SeaBIOS. Boot the kernel with tpm_tis.force=1 or
tpm_tis.interrupts=0. 'force=1' causes the module to ignore the ACPI
TPM interrupt entry and instead probe for interrupts. Since no
interrupts are found to be valid, the driver falls back to polling
mode. And 'interrupts=0' causes the interrupt probing to be skipped,
defaulting to polling mode. So, even though most users set BOTH of
these parameters, they have the same effect on these machines and only
one or the other are necessary.
3. Custom SeaBIOS. Blacklist the tpm_tis module so that it doesn't load
and therefore doesn't issue startup(clear) to the TPM chip.
While there are manual workarounds, a number of people would like the
tpm_tis module to automatically function correctly for stock and custom
SeaBIOS, as we use these machines with those payloads.
Because there are so many users, and flashing the payload is considered
risky, and those who do flash are not usually the ones who build their
firmware, fixing the ACPI table in firmware (which requires flashing)
would not be a general solution. Hopefully Google (or their manufacturing
partners) will correct this in future Chromebooks.
Details about tpm_tis module init using stock SeaBIOS:
The firmware sends a startup(clear). Then the tpm_tis module is loaded
because there is a matching ACPI entry for "IFX0102". By default, module
parameters are interrupts=1 and force=0. I will talk about these default
values, since that is the case that I'd like to fix. force=0 causes the
module to look for an ACPI entry. It finds an entry indicating IRQ 6 and
continues with the tpm_tis_init function.
tpm_tis_init starts in polling mode. It registers the hardware device,
performs some initial setup, queries the chip manufacturer and vendor id,
deterines the chip capabilities (I think they are all enabled), gets
timeouts, does a selftest (which passes), sets up the interrupt and read
queues, and enables chip interrupts. It does all of this in polling mode.
Then, because interrupts=1 and the interrupt was determined from the ACPI
table entry, it skips the code section which probes for available
interrupts. Next, it switches to interrupt mode. It tells the TPM to use
IRQ 6, requests IRQ 6 for use with the driver, does some clean up, and
exits, returning 0.
I've verified that no blocking commands are send to the TPM during the
tpm_tis_init function. Since none are sent, no interrupts fail, and the
attach procedes as normal.
Side note 1: my understanding is that the module exchanges data with the
TPM in the same way whether in polling mode or interrupt mode. These two
modes only indicate how the module determines that it may send additional
commands and/or receive expected data from the TPM. In other words, the
interrupt or polling tell the module when it can continue.
Side note 2: There seems to be a bug that would have prevented detection
of interrupt timeout anyway. I'll follow up with a patch.
Details about tpm_tis module init using custom SeaBIOS:
The same as stock SeaBIOS, except that no startup(clear) has been sent by
the firmware, so tpm_get_timeouts sees that the chip has not been started
and therefore issues a startup(clear) command itself.
Some possible solutions for discussion...
To make stock SeaBIOS work automatically:
1. For all systems in interrupt mode because of an ACPI entry: Use a
non-fragile method to detect correct functioning of the TPM and the
failure of interrupts. If detected, then fall back to polling mode.
Worst case is (slightly?) degraded performance.
2. Same as 1, but only for quirked machines
To make custom SeaBIOS work automatically:
3. For all systems: If error 38 received from selftest at resume, do not
issue subsequent save_state commands before suspend. (This approach has
been tested.)
4. For all systems: Do not send startup(clear) in tpm_get_timeouts unless
a module parameter is set.
5. Same as 4, but only for quirked machines
As suggested by Jason:
6. For all machines in interrupt mode. Use a non-fragile method to detect
the failure of interrupts. Don't attach if detected.
Thanks!