i2c-imc-skylake: close F2 with the register Intel documents

The open question was how to know whether the memory controller is polling
the DIMM thermal sensors, which is what killed the Broadwell-E attempt's
predecessor and what this driver had no answer for.

Intel documents it. The Xeon Processor Scalable Family datasheet volume 2
(reference 614073, section 3.1.9) puts SMBCNTL on the iMC channel function,
device 10 and 12 function 0, at offsets 0xe88 and 0xe98. SMB_TSOD_POLL_EN
is documented as mutually exclusive with SPD command access, so it answers
the question directly. The driver now reads it on every channel at probe
and refuses to bind if it is set.

This is deliberately weaker than the Broadwell-E driver, which switched the
polling off for the duration of a transfer. Reading and declining is a
smaller claim on hardware the driver does not own and needs no write to a
firmware-configured register. It covers the memory controller only; SMM and
a BMC are still out of reach, which is what the opt-in is for.

On the test system all four channels read 0xac000000: polling disabled,
TSOD_PRESENT empty, which also explains why no jc42 ever appeared at
0x18-0x1f on these DIMMs. Offset 0xe0, where the Broadwell driver has its
TSODCNTL, reads zero on all seven PCU functions here: that layout does not
transfer.

Two more measurements, both recorded in the cover letter:

  - the SMBus interface Intel documents, at 0xe80-0xe9c on the iMC, does not
    reach the bus on this platform. Issuing SMBCMD with CMD_TRIGGER sets
    SMB_RDO and clears SMB_BUSY, but returns 0x00 for a populated DIMM at
    0x50, a second one at 0x52 and an empty slot at 0x57 alike, with SMB_SBE
    never set. The path this driver uses returns the correct SPD contents
    and a NACK for the empty slot. The datasheet does not describe PCU
    function 5 at all, so the choice is now stated with data rather than
    left for a reviewer to ask about;
  - writes are issued on the bus: a byte write to an unpopulated address
    returns -ENXIO with the engine reporting the address NACK. This matters
    because SMB_DIS_WRT is set in the documented SMBCNTL and is SMM-writable
    only, so it evidently governs that interface and not this one.

Engine registers sampled every 2 s for an hour with the driver unloaded:
1791 samples, 0 changes.

Add tools/probe-imc-documented.sh, which produced the comparison above.
Smoke test with the new probe check: 15 checks, 0 failures.
This commit is contained in:
Simone
2026-07-26 21:34:47 +02:00
parent 88a8b7eb27
commit b021fe4087
4 changed files with 252 additions and 10 deletions
+44 -9
View File
@@ -74,11 +74,22 @@ So this driver:
previous transaction's data. The engine only ever clears GO, so that
is the single permitted difference between the two words.
What is missing: no equivalent of Broadwell's TSODCNTL has been identified
on this part. Offset 0xe0, where Broadwell has it, reads as zero here. A
system with CLTT enabled is therefore expected to trip the interference
check rather than be arbitrated against. I would rather ship a driver that
detects the condition and refuses than one that quietly races.
- refuses to bind when the memory controller is polling the DIMM thermal
sensors itself. Intel documents SMBCNTL on the iMC channel function
(device 10 and 12, function 0, offsets 0xe88 and 0xe98) in the Xeon
Processor Scalable Family datasheet volume 2, reference 614073, section
3.1.9. Its SMB_TSOD_POLL_EN bit is documented as mutually exclusive
with SPD command access, so it answers directly whether the engine is
in use. On the test system all four channels read 0xac000000: polling
disabled, TSOD_PRESENT mask empty, which also explains why no jc42
device appears at 0x18-0x1f.
This is deliberately weaker than what the Broadwell-E driver did. That one
switched the polling off for the duration of a transfer. Reading the bit
and declining is a smaller claim on hardware the driver does not own, and
it needs no write to a firmware-configured register. It covers the memory
controller only; SMM and a BMC remain out of reach, which is what the
opt-in is for.
Relation to prior work
~~~~~~~~~~~~~~~~~~~~~~
@@ -119,6 +130,7 @@ Changes since v2
default-off gate, which was logging a driver-core error on every boot.
- Add Documentation/i2c/busses/i2c-imc-skylake.rst.
- Drop the ACPI dependency.
- Refuse to bind when the iMC reports TSOD polling enabled.
Validation
~~~~~~~~~~
@@ -132,12 +144,35 @@ Validation
per channel, the default-off gate, and 20 unload/reload cycles: 15
checks, 0 failures, no kernel warning or oops, no interference
reported, every command word confirmed in the register.
- Config space of the PCU function sampled with the driver unloaded: no
register changed on its own, and TSOD_ACTIVE was clear on both channels,
so no firmware activity was observed on this system.
- Engine registers sampled every 2 s for one hour with the driver
unloaded: 1791 samples, 0 changes. No firmware activity was observed
on this system.
- SMBCNTL on all four iMC channels reads 0xac000000: TSOD polling
disabled, TSOD_PRESENT empty.
- Write transactions reach the bus: a byte write to an unpopulated
address returns -ENXIO with the engine reporting the address NACK, so
the write path is issued rather than suppressed. An end-to-end write
to a populated device is not part of this validation; the only
non-SPD device on the test system is an LED controller whose reads are
themselves unreliable, and SPD writes were out of scope.
Still missing: an independent Tested-by, ideally on Skylake-X rather than
Cascade Lake-X, and suspend/resume testing with active I2C clients.
Cascade Lake-X, suspend/resume testing with active I2C clients, and an
end-to-end write to a populated device.
One note on the register interface, since a reader with the datasheet will
ask. That document describes an SMBus interface on the iMC channel
function at 0xe80-0xe9c, with a different encoding from the one this driver
uses on PCU function 5 at 0x9c-0xb8; it does not describe function 5 at all,
covering device 30 functions 0 and 2 only. I tried the documented path on
this system: issuing SMBCMD with CMD_TRIGGER sets SMB_RDO and clears
SMB_BUSY, but returns 0x00 for a populated DIMM at 0x50, for a second one
at 0x52, and for an empty slot at 0x57 alike, with SMB_SBE never set. An
interface that cannot tell a populated slot from an empty one is not
reaching the bus here, while the path this driver uses returns the correct
SPD contents and a NACK for the empty slot. I may well be missing a setup
step; if someone knows what it is, I would rather use the documented
interface.
Tool assistance
~~~~~~~~~~~~~~~
+12 -1
View File
@@ -48,7 +48,18 @@ Do this only on a system where concurrent firmware access has been excluded.
Desktop and HEDT boards have no BMC, but CLTT may still be enabled by the
firmware.
The driver reduces, but cannot remove, the risk:
The driver reduces, but cannot remove, the risk.
At probe it reads SMBCNTL on every iMC channel function (device 10 and 12,
function 0; offsets 0xe88 and 0xe98, documented in the Intel Xeon Processor
Scalable Family datasheet volume 2, reference 614073, section 3.1.9).
``SMB_TSOD_POLL_EN`` in that register says whether the memory controller is
polling the DIMM thermal sensors on its own, which Intel documents as mutually
exclusive with SPD command access. If the bit is set on any channel the driver
refuses to bind: the engine is not ours to drive. This covers the memory
controller, not SMM or a BMC, which remain the reason for the opt-in.
Per transfer:
* every transaction waits for both channels to report idle before it
touches any register;