Commit Graph
6 Commits
Author SHA1 Message Date
Simone 637717dad0 i2c-imc-skylake: guard branch - ECAM accessors close the CF8/CFC SMI window
A conf1 access is two I/O instructions (index on 0xCF8, data on 0xCFC)
serialised against the kernel but not against SMM: an SMI landing between
them, whose handler runs its own CF8/CFC dialogue without restoring the
index, redirects our data phase to whatever register the firmware
addressed last.  The CMD write is covered by the landing check, but the
DATA-register write has no readback, so its payload would land unnoticed
in a foreign config register.  Suspected (not proven) trigger of the ws1
poweroff hang: the wedge sits in the firmware's S5 path and the poison
channel must be invisible to the driver, which this one is.

Map the function's ECAM page from the ACPI MCFG table at probe and route
every register touch through a single MMIO access, which no SMI can
split.  use_ecam=0 (load-time) restores the config-cycle baseline for
A/B; MCFG lookup failure falls back automatically.
2026-08-09 09:48:04 +02:00
Simone 8da98fe1c7 i2c-imc-skylake: guard branch - QUICK emulation and protect_spd
Downstream-only branch, not for submission.  Two additions on top of the
v4 driver:

Approximate SMBus Quick with a byte-data read of register 0 so that
i2cdetect and OpenRGB's DDR4 probe see the devices.  The engine cannot
do a zero-length transaction, so this is a real read against every
probed address - acceptable on a known bus, not as a generic facility,
which is why mainline does not get it.

Add protect_spd (bool, 0644, default on): reject SMBus writes to the
SPD EEPROMs (0x50-0x57) and to the DDR4 protection command addresses
SWPn/CWP (0x30-0x35) with -EPERM, and log the attempt ratelimited.
RSWP cannot be set in-system on this platform (SWPn/CWP require VHV on
SA0), so a driver-level refusal is the strongest available protection
against stray SPD writes from any i2c-dev client.  The page-select
addresses 0x36/0x37 stay writable because ee1004 needs them (Send Byte
page select); ee1004 itself never writes the EEPROM contents.  Toggle
at runtime via /sys/module/i2c_imc_skylake/parameters/protect_spd for
deliberate SPD maintenance, e.g. the documented repair recipe.

The old compat branch predates 1.0.1 (no native Receive Byte, no ee1004
instantiation, no I2C_FUNC_SMBUS_BYTE, so ee1004 cannot even bind) and
is renamed to attic/compat-stale-pre-1.0.1 so nobody builds on it.
2026-07-31 11:26:38 +02:00
Simone 8d70d99ae2 i2c-imc-skylake: hand the engine back quiesced at shutdown
The engine is shared with the firmware, and until now the driver never
returned it: at shutdown the BIOS finds whatever command state the last
transfer left behind.  ws1-mint shows an intermittent poweroff hang
isolated to machine_power_off() -> ACPI _S5 with the engine in session
use; a BIOS SMI handler wedging on a mid-session engine at the S5 trap
is the working hypothesis.  Handing the engine back the way the
firmware left it is correct hygiene regardless of that outcome.

- probe snapshots both pristine CMD words before the driver's first
  transfer, and fails if they cannot be read: an unreadable snapshot
  would turn the handback into writing garbage
- new .shutdown callback (shutdown and kexec): mark both adapters
  suspended, drain the possible in-flight transfer under the lock,
  wait for the engine to go idle, restore the pristine words with GO
  masked.  Best effort: it never blocks the power-off
- resume refreshes the snapshot after the firmware-polling re-check
  passes, since the firmware demonstrably drives the engine across
  suspend; an unreadable refresh leaves the adapters suspended
- the unbind comment now distinguishes unbind (state left as-is, next
  user is another instance of this driver) from shutdown (next user is
  the firmware)

Version 1.0.4.
2026-07-31 11:25:27 +02:00
Simone 694ed6a712 i2c-imc-skylake: instantiate the SPD EEPROMs at probe
Call i2c_register_spd() per adapter, like i801 and piix4, instead of
telling the user to echo into new_device. The helper counts populated
slots from DMI and probes upwards from 0x50 via i2c_new_scanned_device(),
so it claims no address that does not answer; each channel carries half
the DIMMs and the scan is per adapter, so each finds its own. Verified:
four clients on load, two per channel, none on the empty slots, and
decode-dimms works with no manual step.

This needed Receive Byte to be worth doing — without I2C_FUNC_SMBUS_BYTE
ee1004 would not have bound to what was instantiated.

The write_disable variant is deliberate. This part is DDR4 only, where
the two are equivalent (the split gates spd5118 on DDR5), and of two
equivalent calls the one that does not read as "this driver enables SPD
writes" is the better name to leave in a driver whose bus is the memory
bus. In-tree convention is write_enable; the cover letter offers to
switch.

Kconfig gains select I2C_SMBUS.

Out-of-tree, compat.h maps the call onto the older unsplit
i2c_register_spd() where that is what the target kernel has. It is force
included from the Makefile so i2c-imc-skylake.c stays byte-identical to
the submitted file, and the Makefile detects the API by grepping the
target kernel's header rather than testing a version number, which keeps
it correct on backported trees. Builds clean against both 6.8 and 7.0
headers; DKMS 1.0.2 installs on all four kernels here.

test-smoke.sh needed two fixes to keep testing what it claims:

  - A bound driver owns its address, so the raw transaction checks lost
    the SPDs the moment the driver started instantiating them. The script
    now unbinds ee1004 for the duration rather than deleting the clients:
    sysfs delete_device only removes clients that new_device created,
    and unbinding is sufficient because i2c-dev refuses an address only
    while a driver is bound (i2cdev_check: `return dev->driver ? -EBUSY
    : 0`). Rebound from an EXIT trap.

  - Those checks were guarded on an SPD address having been found, and
    when the lookup failed they vanished from the run silently: the suite
    reported "12 passed, 0 failed" while seven checks had not executed.
    Skipped checks are now counted and printed, which is how the above
    was noticed at all.

Smoke suite: 20 passed, 0 failed, 0 skipped. checkpatch --strict 0/0/0,
in-tree W=1 and Sparse clean.
2026-07-27 02:10:33 +02:00
Simone 625bbacc17 i2c-imc-skylake: bump to 1.0.1
Receive Byte and Send Byte. DKMS 1.0.1 built and installed on
6.8.0-134/136 and 7.0.0-14/28; 1.0.0 removed from the tree.
2026-07-27 01:27:26 +02:00
Simone 3cd1d6e0a6 i2c-imc-skylake: split the submission into a PCI patch and the driver
The driver reached the PCU function's config space by walking the ACPI MCFG
table and mapping the ECAM page itself. That is one leaf driver deciding
config-space policy, and no other driver in mainline does it, so it was the
single most likely reason for a NAK.

Move that decision where it belongs: the upstream series is now two patches,
a PCI/x86 accessor that forces the memory-mapped path with the core's
locking, and this driver on top of it. Reviewers on each side now get
something they can act on, and get_maintainer.pl selects the PCI and x86
people by itself.

Correctness work in the same pass:

  - the completion bits are latched, so a command the engine never accepted
    was indistinguishable from a completed one and returned the previous
    transaction's data as valid. Require a positive sign that the engine
    acted on the command;
  - compare the command registers after every transfer against what the
    driver left in them and fail with -EAGAIN on a mismatch. The original
    iMC driver had this check and it is what makes an unarbitrated system
    detectable instead of silently wrong;
  - use the i2c core's suspended-adapter mechanism rather than a private
    flag and -EHOSTDOWN;
  - use devm_mutex_init(), drop the unnecessary pci_enable_device(), and
    return -ENODEV rather than -EPERM from the default-off gate, which was
    printing a driver-core error on every boot;
  - mask GO when restoring a saved command word.

Stop attributing the dropped CF8/CFC write to System Management Mode. The
only evidence was a boot log line naming the access method, which says
nothing about who filters the write. tools/probe-cf8-write.sh is there to
settle it with an MSR_SMI_COUNT measurement.

Add Documentation/i2c/busses/i2c-imc-skylake.rst, which every other PC SMBus
driver has and which was explicitly asked for on the 2020 iMC thread, the
tools/ scripts for the hardware measurements the submission still owes, and
compat/pci-mmcfg-compat.h so the driver still builds out-of-tree against a
kernel without the new accessor while the source stays byte-identical to the
submitted patch.
2026-07-26 19:27:14 +02:00