I was finishing my morning coffee at the Fedora ARM mystery department when a user report came into my attention: the tpm_tis_spi
driver was not working on a board that had a TPM device connected through SPI.
There was no /dev/tpm0
character device present in the system, even when the driver was built as a module and the Device Tree (DT) passed to the kernel had a node with a "infineon,slb9670"
compatible string.
Peter Robinson chimed in and mentioned that he had briefly looked at this case before. The problem, he explained, is that the module isn’t auto-loaded but that manually loading it make things to work.
At the beginning he thought that this was just a common issue of a driver not having module alias information. This would lead to kmod not knowing that the module has to be loaded, when the kernel reported a MODALIAS
uevent as a consequence of the SPI device being registered.
But when checking the module to confirm that theory, he found that there were alias entries:
$ modinfo drivers/char/tpm/tpm_tis_spi.ko | grep alias
alias: of:N*T*Cgoogle,cr50C*
alias: of:N*T*Cgoogle,cr50
alias: of:N*T*Ctcg,tpm_tis-spiC*
alias: of:N*T*Ctcg,tpm_tis-spi
alias: of:N*T*Cinfineon,slb9670C*
alias: of:N*T*Cinfineon,slb9670
alias: of:N*T*Cst,st33htpm-spiC*
alias: of:N*T*Cst,st33htpm-spi
alias: spi:cr50
alias: spi:tpm_tis_spi
alias: acpi*:SMO0768:*
Since the board uses DT to describe the hardware topology, the TPM device should had been registered by the Open Firmware (OF) subsystem. And should cause the kernel to report a "MODALIAS=of:NspiTCinfineon,slb9670"
, which should had matched the "of:N*T*Cinfineon,slb9670"
module alias entry.
But when digging more on this issue, things started to get more strange. Looking at the uevent sysfs entry for this SPI device, he found that the kernel was not reporting an OF modalias but instead a legacy SPI modalias: "MODALIAS=spi:slb9670"
.
But how come? a user asked, the device is registered using DT, not platform code! Where is this modalias coming from? Is this legacy SPI device a ghost?
Peter said that he didn’t believe in paranormal events and that there should be a reasonable explanation. So armed with grep
, he wanted to get to the bottom of this but got preempted by more urgent things to do.
Coincidentally, I had chased down that same ghost before many moons ago. And it’s indeed not a spirit from the board files dimension but only an incorrect behavior in the uevent logic of the SPI subsystem.
The reason is that the SPI uevent handler always reports a MODALIAS
of the form "spi:foobar"
even for devices that are registered through DT. This leads to the situation described above and it’s better explained by looking at the SPI subsystem code:
static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
int rc;
rc = acpi_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
}
Conversely, this is what the platform subsystem uevent handler does (which properly reports OF module aliases):
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device *pdev = to_platform_device(dev);
int rc;
/* Some devices have extra OF data and an OF-style MODALIAS */
rc = of_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
rc = acpi_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
pdev->name);
return 0;
}
Fixing the SPI core would be trivial, but the problem is that there are just too many drivers and Device Trees descriptions that are relying on the current behavior.
It should be possible to change the core, but first all these drivers and DTs have to be fixed. For example, the I2C subsystem had the same issue but has already been resolved.
A workaround then in the meantime could be to add to the legacy SPI device ID table all the entries that are found in the OF device ID table. That way, a platform using for example a DT node with compatible "infineon,slb9670"
will match against an alias "spi:slb9670"
, that will be present in the module.
And that’s exactly what the proposed fix for the tpm_tis_spi
driver does.
$ modinfo drivers/char/tpm/tpm_tis_spi.ko | grep alias
alias: of:N*T*Cgoogle,cr50C*
alias: of:N*T*Cgoogle,cr50
alias: of:N*T*Ctcg,tpm_tis-spiC*
alias: of:N*T*Ctcg,tpm_tis-spi
alias: of:N*T*Cinfineon,slb9670C*
alias: of:N*T*Cinfineon,slb9670
alias: of:N*T*Cst,st33htpm-spiC*
alias: of:N*T*Cst,st33htpm-spi
alias: spi:cr50
alias: spi:tpm_tis_spi
alias: spi:slb9670
alias: spi:st33htpm-spi
alias: acpi*:SMO0768:*
Until the next mystery!
Pingback: Links 16/6/2021: Alpine 3.14.0 and DXVK 1.9 | Techrights
Pingback: Building a retro handheld console with Fedora and a RPi zero | Blog | Javier Martinez Canillas
Pingback: Linux drivers and devices registration, matching, aliases and modules autoloading | Blog | Javier Martinez Canillas