I caught this one the boring way: scrolling dmesg on a Proxmox host while looking for something else entirely. The host is borderlands, one of my personal-side hypervisors, the box that also runs my consolidated Proxmox Backup Server as a guest. Its kernel ring buffer was doing this, over and over, as far back as the buffer went:
tpm tpm0: TPM_LOC_STATE_x.requestAccess timed out
tpm tpm0: TPM_LOC_STATE_x.requestAccess timed out
tpm tpm0: TPM_LOC_STATE_x.requestAccess timed out
Not a burst. Not a boot-time hiccup that settled down. A steady drumbeat, one line (sometimes two) every ten seconds, around the clock. The timestamps stretched back so far that the host's actual boot messages had long since scrolled out of the buffer; the uptime was around twenty-four days and the log was nothing but this. Whatever it was, it had been talking to itself for weeks and nothing had visibly broken.
That combination of perfectly regular, perfectly harmless-looking, and endless is its own kind of interesting. A system that's actually failing tends to fail loudly and once, or escalate. A system repeating the exact same complaint on a fixed cadence forever is usually a loop: something asks, something doesn't answer, a timer fires, and it asks again. The job was to find the loop.
What the message actually says
TPM_LOC_STATE_x isn't an app or a service. It comes from the kernel's tpm_tis driver, the one that speaks to a TPM over the standard TIS (TPM Interface Specification) register interface. The _x is a locality number.
Localities are the part of the TPM spec most people never have to think about. A TPM exposes several parallel access channels, localities 0 through 4, so that different trust domains (firmware, a boot loader, the OS, a late-launch environment) can each talk to the chip through their own door without stepping on each other. Before the driver can issue a command, it has to claim a locality: write a "request access" bit into that locality's status register and then wait for the chip to answer back "granted."
That handshake is what's failing. requestAccess timed out means the driver asked for a locality, started its timer, and the chip never came back to say the access was granted before the timer expired. So it gives up, logs the line, and ten seconds later tries again. There's the loop.
The first instinct is to assume the chip is dying. But a dying chip is rarer than a chip that's simply not being spoken to correctly, and the fixed ten-second cadence smelled far more like a software timer than like failing silicon. So before touching a screwdriver, I wanted three plain facts: is there even a TPM here, is anyone actually using it, and who is driving that ten-second retry.
Triage, in the order that saves the most time
Is a TPM present at all, and which generation?
cat /sys/class/tpm/tpm0/tpm_version_major
# 2
A TPM 2.0 is present and the driver bound to it far enough to publish a sysfs node. So this isn't a phantom device or a stale driver clinging to hardware that got pulled. There's a real 2.0 chip on the other end of that timeout.
Who is holding the device open? This is the question that decided the whole investigation, so it's worth doing thoroughly:
sudo lsof /dev/tpm0 /dev/tpmrm0
sudo fuser -v /dev/tpm0
systemctl status tpm2-abrmd
All three came back empty. Nothing had /dev/tpm0 or the resource-manager node /dev/tpmrm0 open. The tpm2-abrmd access broker, the daemon that would normally sit in front of the chip and multiplex userspace requests, wasn't even running. There was no monitoring agent, no rngd pulling entropy, no measured-boot tooling. Userspace wasn't touching the TPM at all.
That is the pivot of the entire story. If some daemon had been polling the chip every ten seconds, the fix would be "stop the daemon." But nobody was. Which means the ten-second retry wasn't coming from anything above the driver. The driver was doing it on its own.
The loop is the driver waiting on an interrupt
Here's the mechanism. When tpm_tis binds to a chip, it tries to run in interrupt mode: rather than busy-polling a status register to see when the chip has finished, it arms the TPM's interrupt line and goes to sleep, expecting the hardware to raise an IRQ when the locality is granted. It's the efficient path, with no spinning and no wasted cycles.
It only works if the interrupt actually arrives. And on a depressing number of real-world boards, it doesn't: the TPM's interrupt is misrouted in the firmware's ACPI tables, or wired to a pin that never asserts, or the chip advertises an IRQ it doesn't really drive. The bus is electrically fine. You can talk to the chip by polling it without any trouble. But the interrupt never fires. So the driver arms the IRQ, requests the locality, and blocks waiting for a signal that will never come. The only thing that eventually wakes it is its own timeout. It logs requestAccess timed out, and because whatever background housekeeping wanted the chip still wants it, the cycle repeats on the next timer tick. Ten seconds. Forever.
So the log line isn't reporting a broken TPM. It's reporting a broken assumption about how to talk to a perfectly functional one. The chip would answer if the driver would just ask by polling instead of waiting for a doorbell that was never connected.
The decision: do I even need this chip?
Before reaching for a fix I had to answer the question that makes this easy: does anything on borderlands actually depend on the physical TPM?
- The host itself. No measured boot, no Secure Boot chain sealing anything to the TPM's PCRs, nothing storing keys in it. The
lsofemptiness had already proven that at runtime. - The guests. This is the one people second-guess, so it's worth stating plainly: a virtual TPM attached to a VM (for a Windows 11 guest, say) is not backed by the host's physical chip. Proxmox stores vTPM state as a file on your storage and QEMU emulates the device in software. You can blacklist, disable, or physically yank the host's TPM and every guest vTPM keeps working exactly as before.
So the chip was doing nothing for me except generating a log line every ten seconds. That gives three tiers of fix, and the right one is the least destructive that stops the noise, because "I don't use it today" is not the same as "I will never want it," and a working TPM quietly sitting idle is worth more than one I've torn out of the boot path.
The fix: make the driver poll instead of wait
The surgical option is to tell tpm_tis to skip interrupt mode entirely and drive the chip by polling. That keeps the TPM fully present and usable, changing only how the driver waits for it, and it sidesteps the never-fired interrupt completely. It's a single kernel module parameter:
tpm_tis.interrupts=0
The only trick is getting it onto the kernel command line, and Proxmox has two different boot paths depending on how the host was installed. The modern ZFS/UEFI installs are managed by proxmox-boot-tool; everything else boots through plain GRUB. Always check which before editing anything:
proxmox-boot-tool status
# E: /etc/kernel/proxmox-boot-uuids does not exist.
That error is the answer: borderlands is not managed by proxmox-boot-tool. It's a plain-GRUB host, so editing /etc/kernel/cmdline (the systemd-boot path) would have done exactly nothing, which is a genuinely easy way to "apply" a fix that never touches the running kernel. The GRUB path instead:
# /etc/default/grub: append inside the existing quotes, don't replace them
GRUB_CMDLINE_LINUX_DEFAULT="quiet tpm_tis.interrupts=0"
update-grub
reboot
And after it comes back, confirm the argument is actually live rather than trusting that the edit took. Half of "it didn't work" is a fix that never made it into the running kernel:
grep -o 'tpm_tis.interrupts=0' /proc/cmdline # the arg is really there
dmesg | grep -i tpm # and the buffer stays quiet
The follow-up, because I promised one: the maintenance window came and borderlands cycled. The argument took, tpm_tis.interrupts=0 shows up in /proc/cmdline, and the thing that actually matters is what the log did not do afterward. The ten-second requestAccess timed out drumbeat is gone. dmesg | grep -i tpm comes back empty, and it has stayed empty across the days since the reboot rather than going quiet for a minute and resuming. The chip is still present and bindable; the driver just polls it now instead of blocking on a doorbell that was never wired. That's the diagnosis confirmed by the only test that counts, the silence holding.
I'd left the original honest caveat here, that as I first wrote this the confirming reboot was still queued and I wouldn't call it fixed before I'd watched it stay quiet. It stayed quiet.
If polling mode somehow doesn't settle it, meaning the chip is genuinely wedged rather than just misrouted, the next tiers are there, and both are safe precisely because nothing depends on the chip. Blacklist the driver so it never binds:
printf 'blacklist tpm_tis\nblacklist tpm_tis_core\nblacklist tpm\n' \
> /etc/modprobe.d/blacklist-tpm.conf
update-initramfs -u
Or, the most durable option, disable the TPM/PTT/fTPM in the host firmware and take it out of the picture entirely. I'm deliberately trying those last. Ripping the chip out is the fix that feels decisive and forecloses the most: the day I do want measured boot or a host-held key, I'd rather flip one kernel parameter back than reverse a blacklist I've long forgotten writing.
What I'd tell past me
- A perfectly periodic error is a loop, not a failure. Genuine hardware failure is erratic or escalating; the exact same line on a fixed cadence forever is something asking, timing out, and asking again. Find the timer and you've found the bug.
lsofbefore the screwdriver. The single most useful command here wasn't about the TPM at all. It was checking who had the device open. An empty result reframed the whole problem from "the chip is failing" to "nobody's even using it, so why is it busy," which is a completely different and much smaller fix.- Know your host's boot path before you edit it.
proxmox-boot-tool statusversus plain GRUB is a five-second check that decides which file even matters. Editing the wrong one is the most convincing way to apply a fix that changes nothing and then wonder why the symptom survived a reboot. - Prefer the reversible fix for hardware you're not using. A misbehaving-but-idle TPM tempts you to just disable it in the BIOS and move on. Polling mode keeps it alive and working for the cost of one boot argument. "I don't need it today" is a bad reason to make "I need it next year" harder than flipping one flag.
If your kernel log is chanting the same TPM locality timeout at you on a metronome, don't reach for a new motherboard. Check who's holding the chip, which is probably no one, and let the driver poll the interrupt it was never going to receive.