Linux I2C development
 help / color / mirror / Atom feed
* [PATCH v3 0/1] i2c: imc-skylake: add Intel Skylake-X iMC SMBus adapter
@ 2026-07-28 12:24 Simone Chifari
  2026-07-28 12:24 ` [PATCH v3 1/1] " Simone Chifari
  0 siblings, 1 reply; 2+ messages in thread
From: Simone Chifari @ 2026-07-28 12:24 UTC (permalink / raw)
  To: Andi Shyti
  Cc: linux-i2c, linux-kernel, Andy Lutomirski, Stefan Schaeckeler,
	Simone Chifari

The integrated memory controller of Intel Skylake-X and Cascade Lake-X
processors contains an SMBus engine wired to the DDR4 DIMMs.  This driver
exposes its two channels as standard Linux I2C adapters, so that DDR4 SPD
EEPROMs and DIMM thermal sensors can be read with i2c-tools, decode-dimms
and lm-sensors.

v2 was posted as i2c-imc-x299 and received no replies:

  https://lore.kernel.org/linux-i2c/20260620144131.415559-1-simone.chifari@gmail.com/

Correction to v2
~~~~~~~~~~~~~~~~
v2 claimed that firmware filters CF8/CFC config writes to this function and
that the registers can only be reached through the ECAM window.  That claim
was wrong and I am retracting it.

It was never tested directly.  The only evidence behind it was the boot log
line "PCI: Using configuration type 1", which says which accessor the kernel
uses and nothing about a write failing.  Measured on the same board:

  # setpci -s 16:1e.5 9c.L=20085002    # read SPD 0x50, register 0x02
  # setpci -s 16:1e.5 9c.L
  20005002                             # GO consumed
  # setpci -s 16:1e.5 a8.L
  0000500c                             # READ_DONE, no error
  # setpci -s 16:1e.5 b4.L
  0000000c                             # SPD byte 2: DDR4 type code

The command written through CF8/CFC is executed and returns correct data,
and MSR_SMI_COUNT does not move across it.  This driver therefore uses
pci_read_config_dword() and pci_write_config_dword() like any other driver.
There is no ECAM mapping, no MCFG parsing and no PCI-core change in this
series any more.

Firmware arbitration
~~~~~~~~~~~~~~~~~~~~
This is the reason no iMC SMBus driver has ever been merged, and this patch
does not solve it either.  It does make the condition detectable.

Andy Lutomirski's original i2c_imc put it plainly: a BMC, the memory
controller's power management, and possibly SMM all like to touch this bus,
and Intel defined no way to arbitrate between them.  That driver already had
a module parameter called allow_unsafe_access.  Stefan Schaeckeler's 2020
Broadwell rewrite went further and stopped the PCU's TSOD polling for the
duration of a transfer (write 0 to TSODCNTL, wait 10 ms for in-flight
transactions to drain, restore afterwards), because on Broadwell the
original driver's consistency check tripped about every 30 minutes.

  https://lwn.net/Articles/635898/
  https://lore.kernel.org/linux-i2c/1582498270-50674-1-git-send-email-schaecsn@gmx.net/

So this driver:

  - keeps the default-off allow_unsafe_access gate, deliberately the same
    name as the original;
  - serializes both channels under one mutex and waits for the whole engine
    to be idle before touching any register;
  - saves the command state of both channels, clears TSOD_ACTIVE for the
    duration of the transfer, and restores both afterwards;
  - after every transfer compares the command registers against what it
    left in them and fails the transfer with -EAGAIN if anything else
    changed.  This is the check the original driver had, and it is what
    makes an unarbitrated system detectable rather than silently wrong;
  - reads the command word back and requires it to be the one just
    written, because the done bits are latched.  With the driver unloaded
    and nothing running, STATUS on the test system reads 0x0000300c:
    READ_DONE and WRITE_DONE both still set from an earlier transaction.
    Without the check, a command word that never reaches the register is
    indistinguishable from a completed transfer and the caller receives the
    previous transaction's data.  The engine only ever clears GO, so that
    is the single permitted difference between the two words.

  - 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
~~~~~~~~~~~~~~~~~~~~~~
There is no iMC I2C driver in mainline.  Lutomirski's i2c-imc was an RFC;
the 2020 resend and github.com/Linux4/i2c-imc are out of tree.  Neither can
be extended to cover this part: the device ID (0x2085 vs 0x3ca8/0x6fa8) and
the register layout (0x9C-0xB8 vs 0x180-0x188) differ.  A separate file is
cleaner than a hw_data table.

The register encoding was cross-checked against an independent Windows
implementation for the same engine, which predates this work:

  https://github.com/namazso/PawnIO.Modules/blob/c975ca1d1b8a9c7473a175fa1ca24d83b6cbc8f3/SmbusIntelSkylakeIMC.p

It also implements SMBus BYTE through a pointer-select bit, without saying
which bit.  That bit is 18 here.  The datasheet gave it away: SMBCMD on the
iMC channel functions places PNTR_SEL immediately above WORD_ACCESS, and
word access on the PCU function is bit 17.

Bit 18 is the only part of this driver that rests on an undocumented
encoding, so it is worth saying exactly what was measured rather than
asserting it works.  With the bit set on a read, eight consecutive
transfers to an SPD EEPROM returned bytes 0x01 through 0x08 in order,
matching an ordinary dump of the same range.  That is the auto-increment
of a Receive Byte; a transfer that still named a register would have
returned the same byte eight times.  With the bit set on a write, a Send
Byte to the DDR4 page-select addresses moves the 256-byte window: byte
0x00 stops reading as the JEDEC 0x23 after selecting page 1 and returns
to it after selecting page 0.

ee1004 consequently binds, and decode-dimms reads all four DIMMs on this
system with both SPD CRCs valid on each.  jc42 binds where a sensor is
populated.  i2cdetect scans in read mode.

With Receive Byte in place the driver can also do what the other SMBus
host drivers do and call i2c_register_spd() per adapter, so the SPD
EEPROMs are instantiated at probe rather than by hand.  The helper counts
the populated slots from DMI and probes upwards from 0x50, leaving alone
any address that does not answer; each channel carries half the DIMMs and
the scan is per adapter, so each finds its own.  Nothing else is
instantiated, jc42 included: there is no firmware description of these
buses and this driver does not scan for anything but the SPDs.

I used the write_disable variant.  This part is DDR4 only, where the two
are equivalent - the distinction gates spd5118 on DDR5 - and between two
equivalent calls the one that does not read as "this driver enables SPD
writes" seemed the better thing to leave in a memory-bus driver.  Happy
to switch to write_enable for consistency with i801 and piix4 if you
prefer the convention.

SMBus Quick is still not implemented, and not only because the engine has
no obvious encoding for it.  A write to the 0x30-0x37 range is how an
EE1004 SPD is write-protected, permanently on many modules.  An adapter
whose bus is the memory bus should not advertise a probe that writes.

Changes since v2
~~~~~~~~~~~~~~~~
  - Retract the CF8/CFC claim; use the ordinary config accessors.  The
    driver no longer maps anything.
  - Rename i2c-imc-x299 to i2c-imc-skylake; the engine is in the CPU, not
    the chipset.
  - Add the default-off allow_unsafe_access gate.
  - Wait for both channels to be idle before touching the data latch.
  - Preserve and restore command and TSOD state for both channels.
  - Validate READ_DONE, WRITE_DONE and the hardware error state.
  - Detect interference from another master and report it as -EAGAIN.
  - Read the command word back and require it to be the one written.
  - Add bounded command-toggle recovery for a stuck BUSY state.
  - Add WORD_DATA support with the hardware byte ordering.
  - Reject I2C_M_TEN explicitly and validate transfer direction.
  - Use the i2c core's suspended-adapter mechanism instead of a private
    flag and a non-standard errno.
  - Use devm_mutex_init() and devm-managed adapters; drop the unnecessary
    pci_enable_device(); return -ENODEV rather than -EPERM from the
    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.
  - Correct the claim that BYTE_DATA and WORD_DATA cover ee1004: they do
    not, ee1004 also needs Receive Byte and Send Byte.
  - Implement both, on the pointer-select bit, so ee1004 binds and
    decode-dimms works.
  - Instantiate the SPD EEPROMs with i2c_register_spd() instead of
    leaving it to the user.

Validation
~~~~~~~~~~
  - In-tree build, W=1, x86_64 GCC and arm64 Clang COMPILE_TEST: no
    diagnostics.
  - checkpatch.pl --strict: clean.
  - Sparse with __CHECK_ENDIAN__: clean.
  - Hardware test on one Intel Core i9-10900X (Cascade Lake-X) system with
    four DDR4 DIMMs: both adapters, four SPD EEPROMs, BYTE_DATA, WORD_DATA
    byte order, Receive Byte tracking the EEPROM pointer, Send Byte moving
    the SPD page and putting it back, ENXIO for an absent device, 100
    concurrent reads per channel, the default-off gate, and 20
    unload/reload cycles: 19 checks, 0 failures, no kernel warning or oops,
    no interference reported, every command word confirmed in the register.
  - i2c_register_spd() instantiated ee1004 on all four populated SPD
    addresses at probe, two per channel, and claimed none of the empty
    ones.  decode-dimms then decoded all four modules, each with the CRC
    of bytes 0-125 and of bytes 128-253 valid.  The part number reads out
    of page 1, so the page select is exercised end to end.  The four
    module serial numbers were identical before and after every
    experiment in this series.
  - Engine registers sampled every 2 s for one hour with the driver
    unloaded: 1791 samples, 0 changes.  No firmware activity while the
    system is up.
  - Suspend and resume, s2idle and S3, with continuous traffic on both
    adapters: transfers recover and nothing complains.  Across S3 the
    firmware demonstrably drives the engine.  Both channels, sampled
    immediately before suspend and immediately after resume:

      DATA   0x2000b600 -> 0x20005000
      STATUS 0x0000500c -> 0x00005004

    The command word came back addressing SPD 0x50 for a read, and the
    status went from both done bits latched to READ_DONE alone.  Nothing in
    Linux issued that: the adapter was marked suspended and userspace was
    frozen.  This is consistent with firmware reading SPD during memory
    training on resume.  It is the only direct observation of a second
    master on this engine I have, and it is the concrete reason the driver
    restores command state per transfer and compares it afterwards.
  - SMBCNTL on all four iMC channels reads 0xac000000: TSOD polling
    disabled, TSOD_PRESENT empty.
  - Writes validated end to end against a populated device: a 12-write
    frame to an LED controller at 0x27, across both channels, every write
    acknowledged, no NACK, and the device applied the result.  A byte
    write to an unpopulated address returns -ENXIO with the engine
    reporting the address NACK.  No SPD was written at any point, and the
    four SPD EEPROMs were verified present with valid CRCs before and
    after.

Still missing: an independent Tested-by, ideally on Skylake-X rather than
Cascade Lake-X.

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
~~~~~~~~~~~~~~~
Per Documentation/process/generated-content.rst: this work was developed
with an AI coding assistant, run interactively rather than autonomously.

  - What: Claude Code, model claude-opus-5.
  - Where: it contributed to the transaction state machine, the .rst
    documentation, the commit message and this cover letter.  The register
    decoding is mine.
  - How it was used: iteratively, one reviewed change at a time, in
    response to specific requests, not from a single generating prompt.  A
    representative request is "the done bits are latched; show me how a
    command that is never accepted can be mistaken for a completed one, and
    make that case detectable", which produced imc_engine_responded().  It
    also designed the measurement that retracted the CF8/CFC claim above,
    after asking why that claim had never been tested directly.
  - Testing: every revision was built with W=1, checked with
    checkpatch --strict and sparse, and tested on the hardware by me.

I have reviewed all of it, I understand it, and I take responsibility for
it.

Simone Chifari (1):
  i2c: imc-skylake: add Intel Skylake-X iMC SMBus adapter

 Documentation/i2c/busses/i2c-imc-skylake.rst | 178 +++++
 Documentation/i2c/busses/index.rst           |   1 +
 MAINTAINERS                                  |   7 +
 drivers/i2c/busses/Kconfig                   |  27 +
 drivers/i2c/busses/Makefile                  |   1 +
 drivers/i2c/busses/i2c-imc-skylake.c         | 734 +++++++++++++++++++
 6 files changed, 948 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-imc-skylake.rst
 create mode 100644 drivers/i2c/busses/i2c-imc-skylake.c


base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
-- 
2.43.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH v3 1/1] i2c: imc-skylake: add Intel Skylake-X iMC SMBus adapter
  2026-07-28 12:24 [PATCH v3 0/1] i2c: imc-skylake: add Intel Skylake-X iMC SMBus adapter Simone Chifari
@ 2026-07-28 12:24 ` Simone Chifari
  0 siblings, 0 replies; 2+ messages in thread
From: Simone Chifari @ 2026-07-28 12:24 UTC (permalink / raw)
  To: Andi Shyti
  Cc: linux-i2c, linux-kernel, Andy Lutomirski, Stefan Schaeckeler,
	Simone Chifari

The integrated memory controller of Intel Skylake-X and Cascade Lake-X
processors contains an SMBus engine wired to the DDR4 DIMMs.  It reaches
the SPD EEPROMs at 0x50-0x57 and the thermal sensors at 0x18-0x1f, on
two independent channels.  Expose the two channels as standard I2C
adapters so i2c-tools, decode-dimms and lm-sensors can use them.

The engine is driven through the config space of the PCU function
8086:2085, at offsets 0x9C-0xB8, with the ordinary config accessors.

It has no arbitration mechanism.  SMM, a BMC and the memory controller's
own closed-loop thermal throttling can drive the same registers, and the
PCI ID does not tell the driver whether any of them is active, so keep
the driver default-off behind allow_unsafe_access, as the earlier iMC
drivers for Sandy Bridge-EP and Broadwell-E did.

Refuse to bind outright when the memory controller is polling the DIMM
thermal sensors itself.  The Intel Xeon Processor Scalable Family datasheet
volume 2 (reference 614073, section 3.1.9) documents SMBCNTL on the iMC
channel function, device 10 and 12 function 0, at offsets 0xe88 and 0xe98.
Its SMB_TSOD_POLL_EN bit is documented as mutually exclusive with SPD
command access, so it answers directly whether the engine is already in
use.  Read it on every channel at probe.  This is weaker than the
Broadwell-E driver, which switched the polling off for the duration of a
transfer; 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, not SMM or a BMC.

On top of that gate, serialize both channels under one mutex, wait for
the whole engine to be idle before touching any register, save the
command state of both channels and clear TSOD_ACTIVE for the duration of
the transfer, and restore both afterwards.  Then compare the command
registers against what the driver left in them and fail the transfer
with -EAGAIN when anything else changed: without that check a second
master using the engine is silently wrong rather than merely
unsupported.

The completion bits are latched and no way to clear them has been found.
With the driver unloaded and nothing running, STATUS on the test system
reads 0x0000300c, both READ_DONE and WRITE_DONE still set from an
earlier transaction.  A command word that never reaches the register is
therefore indistinguishable from a completed transfer: the stale word
has GO already clear, STATUS already shows a DONE, and the caller
receives the previous transaction's data as valid.  Read the command
word back and require it to be the one just written.  The engine only
ever clears GO, so that is the single permitted difference.

Support SMBus Receive Byte and Send Byte, BYTE_DATA and WORD_DATA, and
reject 10-bit addressing and unsupported protocols explicitly.  That
covers jc42 and ee1004, so decode-dimms reads the whole 512-byte DDR4
SPD including the fields on page 1.

Receive Byte and Send Byte need a command word that puts no register byte
on the bus, which the engine encodes in bit 18.  That bit is not
documented for this function, and it is the only undocumented encoding
this driver relies on, so it was pinned down rather than assumed.  SMBCMD
on the iMC channel function places PNTR_SEL immediately above WORD_ACCESS,
and word access on the PCU function is bit 17.  With bit 18 set on a read,
eight consecutive transfers to an SPD EEPROM returned bytes 0x01 through
0x08 in order, matching an ordinary dump of the same range: that is the
auto-increment of a Receive Byte, and a transfer still naming a register
would have returned the same byte eight times.  With it set on a write, a
Send Byte to the DDR4 page-select addresses moves the 256-byte window and
moves it back.

With Receive Byte available, instantiate the SPD EEPROMs the way the other
SMBus host drivers do, with i2c_register_spd() per adapter, rather than
leaving it to the user.  The helper counts the populated slots from DMI
and probes upwards from 0x50, 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.  Nothing else is instantiated, jc42 included:
there is no firmware description of these buses and this driver does not
scan for anything but the SPDs.

The write_disable variant is used deliberately.  This part is DDR4 only,
where the two are equivalent - the distinction 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.

Do not implement SMBus Quick.  Besides having no obvious encoding here, a
write into the 0x30-0x37 range is how an EE1004 SPD is write-protected,
permanently on many modules.  An adapter whose bus is the memory bus
should not advertise a probe that writes; i2cdetect scans these buses in
read mode.

Link: https://lore.kernel.org/linux-i2c/20260620144131.415559-1-simone.chifari@gmail.com/
Assisted-by: Claude-Code:claude-opus-5 checkpatch sparse
Signed-off-by: Simone Chifari <simone.chifari@gmail.com>
---
 Documentation/i2c/busses/i2c-imc-skylake.rst | 178 +++++
 Documentation/i2c/busses/index.rst           |   1 +
 MAINTAINERS                                  |   7 +
 drivers/i2c/busses/Kconfig                   |  27 +
 drivers/i2c/busses/Makefile                  |   1 +
 drivers/i2c/busses/i2c-imc-skylake.c         | 734 +++++++++++++++++++
 6 files changed, 948 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-imc-skylake.rst
 create mode 100644 drivers/i2c/busses/i2c-imc-skylake.c

diff --git a/Documentation/i2c/busses/i2c-imc-skylake.rst b/Documentation/i2c/busses/i2c-imc-skylake.rst
new file mode 100644
index 000000000..a1babbb7d
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-imc-skylake.rst
@@ -0,0 +1,178 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============================
+Kernel driver i2c-imc-skylake
+=============================
+
+Supported adapters:
+  * Intel Skylake-X / Cascade Lake-X integrated memory controller (iMC)
+    SMBus engine, PCU function 8086:2085 (socket LGA 2066, platform X299)
+
+Author: Simone Chifari <simone.chifari@gmail.com>
+
+
+Description
+-----------
+
+The integrated memory controller of Intel Skylake-X and Cascade Lake-X
+processors contains an SMBus engine wired to the DDR4 DIMMs.  It reaches the
+SPD EEPROMs (0x50-0x57) and the thermal sensors (TSOD, 0x18-0x1f) of the
+installed modules, plus whatever else a particular module carries on those
+lines.
+
+The engine has two independent channels.  DIMM slots 1 and 2 are on channel 0,
+slots 3 and 4 on channel 1, so the driver registers two i2c adapters::
+
+    $ i2cdetect -l | grep iMC
+    i2c-6   smbus   iMC SMBus Skylake-X channel 0   SMBus adapter
+    i2c-7   smbus   iMC SMBus Skylake-X channel 1   SMBus adapter
+
+Both channels share one hardware engine, so the driver serializes every
+transaction across both adapters.
+
+
+This driver is not enabled by default
+-------------------------------------
+
+The SMBus engine has no arbitration mechanism.  System Management Mode, a BMC,
+and the memory controller's own closed-loop thermal throttling (CLTT) can all
+drive the same registers, and nothing in the PCI ID tells the driver whether
+any of them is doing so on a given system.  Two masters using the engine at the
+same time can send a transaction to the wrong address or return the wrong data.
+
+The driver therefore refuses to bind unless the operator opts in::
+
+    modprobe i2c-imc-skylake allow_unsafe_access=1
+
+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.
+
+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;
+  * the previous command state of both channels is saved, the TSOD-active
+    state is cleared for the duration of the transfer, and both are restored
+    afterwards;
+  * after each transfer the command registers are compared against what the
+    driver left in them.  A difference means another master used the engine,
+    and the transfer is failed with ``-EAGAIN`` rather than reported as
+    successful.
+
+The last check is what makes an unarbitrated system detectable: if the log
+shows
+
+  ``chN command changed under us (...): another master is using the engine``
+
+then firmware is using the engine and the driver should not be loaded on that
+system.
+
+
+Config space access
+-------------------
+
+The engine's registers live at config space offsets 0x9C-0xB8 of the PCU
+function and are reached with the ordinary ``pci_read_config_dword()`` and
+``pci_write_config_dword()``.  Nothing special is required.
+
+Supported transactions
+----------------------
+
+The driver implements SMBus Receive Byte and Send Byte, Read/Write Byte Data
+and Read/Write Word Data.
+
+That covers ``jc42`` (TSOD) and ``ee1004``, so ``decode-dimms`` reads the whole
+512-byte DDR4 SPD, including the manufacturer and part-number fields that live
+on page 1.
+
+Receive Byte and Send Byte need a command word that puts no register byte on
+the bus.  The engine encodes that in bit 18, which is not documented for this
+function.  It was found by noting that the interface Intel does document for
+the iMC channel functions (SMBCMD, datasheet reference 614073, section 3.1.8)
+places ``PNTR_SEL`` immediately above ``WORD_ACCESS``, and that word access
+here is bit 17.  With the bit set, consecutive reads of an SPD EEPROM return
+consecutive bytes, which is the auto-increment behaviour of a Receive Byte and
+cannot be produced by a transfer that names a register.
+
+SMBus Quick is not implemented.  ``i2cdetect`` therefore has to be run in
+read mode::
+
+    $ i2cdetect -y -r 6
+         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
+    20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
+    30: 30 31 -- -- 34 35 36 -- -- -- -- -- -- -- -- --
+    50: 50 -- 52 -- -- -- -- -- -- -- -- -- -- -- -- --
+
+Not advertising Quick is deliberate as well as accurate.  A write to the
+0x30-0x37 range is how an EE1004 SPD is write-protected, permanently on many
+modules, so an adapter on a memory bus should not offer probing that writes.
+
+Block transfers are not implemented.  The engine has block primitives, but no
+device on this bus needs them.
+
+Word transfers use the standard SMBus byte order, so ``jc42`` reading through
+``i2c_smbus_read_word_swapped()`` gets the value it expects.
+
+
+Instantiating clients
+---------------------
+
+SPD EEPROMs are instantiated at probe with ``i2c_register_spd()``, like the
+other SMBus host drivers.  It counts the populated slots from DMI and probes
+from 0x50 upwards, so an address that does not answer is left alone.  Each
+channel carries half the DIMMs and the scan runs per adapter, so each finds
+its own::
+
+    i2c i2c-6: Successfully instantiated SPD at 0x50
+    ee1004 6-0050: 512 byte EE1004-compliant SPD EEPROM, read-only
+
+``decode-dimms`` therefore works with no manual step.
+
+Nothing else is instantiated: there is no firmware description of these buses
+and the driver does not scan for anything but the SPDs.  ``jc42`` has to be
+added by hand where a thermal sensor is populated::
+
+    # echo jc42 0x18 > /sys/bus/i2c/devices/i2c-6/new_device
+
+Whether one is populated is visible in ``SMBCNTL.TSOD_PRESENT``; on the
+development system that mask is empty and no ``jc42`` binds.
+
+Two things about the SPDs are worth knowing on this bus.
+
+A DDR4 SPD is a 512-byte array reached through a 256-byte window, and which
+half is visible is a property of the bus, not of the transfer.  ``ee1004``
+selects a page when it needs one and leaves it selected, so a raw ``i2cget``
+issued afterwards may be looking at page 1.  Select page 0 explicitly before
+reading SPD by hand::
+
+    # i2cset -y 6 0x36 0x00 c
+
+And ``ee1004`` owns those addresses once bound, so userspace cannot reach them
+through ``/dev/i2c-*`` any more.  This is ordinary I2C behaviour, but it is
+worth stating here because the userspace tools that motivate this driver share
+the bus with the SPDs.  Read the SPD through the driver instead::
+
+    $ cat /sys/bus/i2c/drivers/ee1004/6-0050/eeprom | hexdump -C
+
+or, if an address really is needed raw, release it::
+
+    # echo 0x50 > /sys/bus/i2c/devices/i2c-6/delete_device
+
+Module parameters
+-----------------
+
+allow_unsafe_access
+  Bool, read-only after load, defaults to false.  The driver does not bind
+  unless this is set.  See the section above.
diff --git a/Documentation/i2c/busses/index.rst b/Documentation/i2c/busses/index.rst
index 5e4077b08..2d503d59d 100644
--- a/Documentation/i2c/busses/index.rst
+++ b/Documentation/i2c/busses/index.rst
@@ -15,6 +15,7 @@ I2C Bus Drivers
    i2c-amd-mp2
    i2c-diolan-u2c
    i2c-i801
+   i2c-imc-skylake
    i2c-ismt
    i2c-mlxcpld
    i2c-nforce2
diff --git a/MAINTAINERS b/MAINTAINERS
index c8d4b913f..17bc737b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13265,6 +13265,13 @@ S:	Maintained
 F:	drivers/platform/x86/intel/int3472/
 F:	include/linux/platform_data/x86/int3472.h
 
+INTEL SKYLAKE-X IMC SMBUS DRIVER
+M:	Simone Chifari <simone.chifari@gmail.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+F:	Documentation/i2c/busses/i2c-imc-skylake.rst
+F:	drivers/i2c/busses/i2c-imc-skylake.c
+
 INTEL SPEED SELECT TECHNOLOGY
 M:	Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
 L:	platform-driver-x86@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 8c935f867..deafd7890 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -180,6 +180,33 @@ config I2C_I801_MUX
 	  Optional support for multiplexed SMBUS on certain systems with
 	  more than 8 memory slots.
 
+config I2C_IMC_SKYLAKE
+	tristate "Intel Skylake-X iMC SMBus adapter"
+	depends on PCI && (X86_64 || COMPILE_TEST)
+	select I2C_SMBUS
+	help
+	  Say Y here if you want kernel support for the integrated memory
+	  controller (iMC) SMBus engine found in Intel Skylake-X / Cascade
+	  Lake-X processors (socket LGA 2066, platform X299, PCU function
+	  8086:2085).
+
+	  Two I2C adapters are registered, one per hardware SMBus channel,
+	  allowing access to DDR4 DIMM SPD EEPROMs (0x50-0x57) and thermal
+	  sensors from userspace via standard i2c-tools and lm-sensors.
+	  SPD EEPROMs are instantiated automatically from DMI, so decode-dimms
+	  works without any manual step.
+
+	  Firmware, SMM, a BMC or CLTT may drive the same engine and no
+	  generic arbitration mechanism is known.  The driver therefore
+	  refuses to bind unless the allow_unsafe_access module parameter
+	  is enabled.  See Documentation/i2c/busses/i2c-imc-skylake.rst.
+
+	  If unsure, say N.  This driver is only useful on Intel X299 desktop
+	  / HEDT systems with the Skylake-X or Cascade Lake-X CPU.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-imc-skylake.
+
 config I2C_ISCH
 	tristate "Intel SCH SMBus 1.0"
 	depends on PCI && HAS_IOPORT
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 547123ab3..3f45fb8ca 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
 obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
 obj-$(CONFIG_I2C_CHT_WC)	+= i2c-cht-wc.o
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
+obj-$(CONFIG_I2C_IMC_SKYLAKE)	+= i2c-imc-skylake.o
 obj-$(CONFIG_I2C_ISCH)		+= i2c-isch.o
 obj-$(CONFIG_I2C_ISMT)		+= i2c-ismt.o
 obj-$(CONFIG_I2C_NFORCE2)	+= i2c-nforce2.o
diff --git a/drivers/i2c/busses/i2c-imc-skylake.c b/drivers/i2c/busses/i2c-imc-skylake.c
new file mode 100644
index 000000000..0c5018e7e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imc-skylake.c
@@ -0,0 +1,734 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Skylake-X iMC SMBus I2C adapter.
+ *
+ * The integrated memory controller (iMC) on Intel Skylake-X / Cascade Lake-X
+ * processors contains an SMBus engine wired to the DDR4 DIMMs.  It reaches the
+ * SPD EEPROMs (0x50-0x57) and the thermal sensors (0x18-0x1f) of the installed
+ * modules.  The engine is driven through the PCI configuration space of the
+ * Sky Lake-E PCU function (8086:2085).  This driver presents it as two standard
+ * Linux I2C adapters - one per hardware SMBus channel - so that i2c-tools,
+ * decode-dimms and lm-sensors can use it without bespoke sysfs hacks.
+ *
+ * Per-channel register triple within the config space of the function:
+ *                  ch0     ch1
+ *     CTRL (data)  0xB4    0xB8   write: data byte in bits[23:16]; read: low byte
+ *     DATA (cmd)   0x9C    0xA0   command toggle | GO | address | register
+ *     STATUS       0xA8    0xAC   bit0 BUSY, bit1 ERROR/NACK,
+ *                                 bit2 READ_DONE, bit3 WRITE_DONE
+ *   SMBus command byte (DATA bits[15:8]) = (rw << 7) | addr7: the 7-bit slave
+ *   address with bit7 = direction (1 write / 0 read).  The register/offset goes
+ *   in DATA[7:0].  So 0x50 reads SPD EEPROM 0x50.  This was decoded and
+ *   confirmed on hardware, and cross-checked against an independent Windows
+ *   implementation of the same engine.
+ *
+ * The two channels are independent SMBus buses (DIMMs 1,2 on ch0; DIMMs 3,4 on
+ * ch1), hence two i2c_adapter instances exposed as separate /dev/i2c-* nodes.
+ *
+ * Bus arbitration / concurrency with firmware:
+ *   The driver cannot coordinate with SMM, a BMC, or the iMC's own closed-loop
+ *   thermal throttling (CLTT), and the PCI ID alone does not prove that none of
+ *   them is active.  Binding is therefore disabled by default and requires
+ *   allow_unsafe_access=1, following the same choice made by the earlier iMC
+ *   drivers for Sandy Bridge-EP and Broadwell-E.  On top of that, transactions
+ *   are serialized across both channels, wait for the complete engine to become
+ *   idle, temporarily clear TSOD_ACTIVE, restore the previous command state,
+ *   and verify afterwards that no other master modified the command registers
+ *   while the transfer was in flight.
+ *
+ *   Not implemented: the Broadwell-E driver additionally stops the PCU's TSOD
+ *   polling for the duration of a transfer (write 0 to the polling interval,
+ *   wait 10 ms for in-flight transactions to drain, restore afterwards).  The
+ *   equivalent register has not been identified on this part, so a system with
+ *   CLTT enabled is expected to trip the interference check below rather than
+ *   to be arbitrated against.
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+/* PCI id of the Sky Lake-E PCU function carrying the SMBus engine */
+#define PCU_DEVICE	0x2085
+
+/*
+ * The iMC channel function, device 10 and 12 function 0, carries the SMBus
+ * control register documented in the Intel Xeon Processor Scalable Family
+ * datasheet volume 2 (reference 614073) section 3.1.9.  Only SMBCNTL is read
+ * here, and only to find out whether the hardware is polling the DIMM thermal
+ * sensors on its own.
+ */
+#define IMC_CHANNEL_DEVICE	0x2040
+#define IMC_SMBCNTL(ch)		(0xE88 + (ch) * 0x10)
+#define SMBCNTL_TSOD_POLL_EN	BIT(8)
+#define SMBCNTL_TSOD_PRESENT	GENMASK(7, 0)
+
+/* per-channel register offsets in the function's config space */
+#define CH0_CTRL	0xB4
+#define CH0_DATA	0x9C
+#define CH0_STAT	0xA8
+#define CH1_CTRL	0xB8
+#define CH1_DATA	0xA0
+#define CH1_STAT	0xAC
+
+/*
+ * Command word written to the DATA register:
+ *   bit29       = command toggle
+ *   bit20       = TSOD active state, preserved across transfers
+ *   bit19       = GO
+ *   bit17       = word transfer
+ *   bits[15:8]  = SMBus command byte = (rw << 7) | addr7
+ *                   rw bit (0x80): 1 = write, 0 = read
+ *                   addr7        : 7-bit SMBus slave address
+ *   bits[7:0]   = register/offset within the addressed device
+ * For a write the data byte is latched into CTRL[23:16] beforehand.  This
+ * encoding was confirmed on hardware: command 0x50 reads SPD EEPROM 0x50
+ * (DDR4 signature).
+ */
+#define COMMAND_TOGGLE	BIT(29)
+#define GO_BIT		BIT(19)		/* start transaction */
+#define TSOD_ACTIVE_BIT	BIT(20)
+#define WORD_BIT	BIT(17)		/* 16-bit word transfer (vs 8-bit byte) */
+/*
+ * Address-only transfer: the register byte in bits[7:0] is not put on the bus.
+ * A read then returns the byte at the device's own pointer (SMBus Receive
+ * Byte) and a write sends the data byte alone (SMBus Send Byte).
+ *
+ * The bit is not documented for this function.  It was found by noting that
+ * the interface Intel does document for the iMC channel functions (SMBCMD,
+ * datasheet ref. 614073 section 3.1.8) places PNTR_SEL immediately above
+ * WORD_ACCESS, and that word access here is bit 17.  Confirmed on hardware:
+ * with the bit set, eight consecutive reads of an SPD EEPROM returned bytes
+ * 0x01 through 0x08 in order, matching an ordinary dump of the same range,
+ * which is the auto-increment behaviour of a Receive Byte and cannot be
+ * produced by a transfer that names a register.
+ */
+#define PNTR_SEL_BIT	BIT(18)
+#define WRITE_OPERATION	BIT(15)
+#define COMMAND_PREFIX	(COMMAND_TOGGLE | GO_BIT)
+#define COMMAND_KEEP_MASK	(~TSOD_ACTIVE_BIT)
+/*
+ * Command bits this driver produces itself.  Everything outside this mask
+ * belongs to whoever else is driving the engine, so a change there during a
+ * transfer means interference.
+ */
+#define COMMAND_OUR_BITS	(COMMAND_TOGGLE | GO_BIT | WORD_BIT | \
+				 PNTR_SEL_BIT | GENMASK(15, 0))
+#define STAT_BUSY	BIT(0)		/* low bit set while transaction in flight */
+#define STAT_ERROR	BIT(1)
+#define STAT_READ_DONE	BIT(2)
+#define STAT_WRITE_DONE	BIT(3)
+#define STAT_ANY_DONE	(STAT_ERROR | STAT_READ_DONE | STAT_WRITE_DONE)
+
+/*
+ * Polling bounds.  Transactions on the tested system complete in a few
+ * milliseconds; these are upper bounds that avoid busy-spinning and cover
+ * device clock stretching, not a measured multi-platform worst case.  The
+ * mutex is held across a whole transfer, so the worst case a caller on the
+ * other channel can wait for is the sum of all of them, roughly 750 ms.
+ */
+#define IMC_POLL_US		10
+#define IMC_IDLE_TIMEOUT_US	50000
+#define IMC_GO_TIMEOUT_US	200000
+#define IMC_DONE_TIMEOUT_US	50000
+
+static bool allow_unsafe_access;
+module_param(allow_unsafe_access, bool, 0444);
+MODULE_PARM_DESC(allow_unsafe_access,
+		 "allow access without firmware/SMM arbitration (unsafe)");
+
+struct imc_chan {
+	unsigned int ctrl, data, stat;
+	int idx;			/* channel index 0 or 1 */
+};
+
+static const struct imc_chan imc_chans[2] = {
+	{ CH0_CTRL, CH0_DATA, CH0_STAT, 0 },
+	{ CH1_CTRL, CH1_DATA, CH1_STAT, 1 },
+};
+
+/* one driver state object, shared by both per-channel adapters */
+struct imc_smbus {
+	struct pci_dev *pdev;		/* config space carrying the engine */
+	struct device *dev;		/* &pdev->dev, for dev_*() logging */
+	struct mutex lock;		/* serialises all SMBus transactions */
+					/* needed: both channels share one engine */
+	struct i2c_adapter adap[2];	/* one per hardware channel */
+	int io_err;			/* sticky config-access error, under lock */
+};
+
+struct imc_xfer_state {
+	u32 command[ARRAY_SIZE(imc_chans)];
+	bool restore[ARRAY_SIZE(imc_chans)];
+};
+
+/*
+ * Register accessors.  A config-space failure is recorded in s->io_err and
+ * reported once, at the end of the transfer, so the transaction logic does not
+ * have to check a return value on every register touch.  A failed read yields
+ * all-ones, which no polling loop mistakes for a completed transaction.
+ */
+static u32 imc_reg(struct imc_smbus *s, unsigned int off)
+{
+	u32 val;
+	int ret;
+
+	ret = pci_read_config_dword(s->pdev, off, &val);
+	if (ret) {
+		s->io_err = pcibios_err_to_errno(ret);
+		return ~0U;
+	}
+
+	return val;
+}
+
+static void imc_set(struct imc_smbus *s, unsigned int off, u32 val)
+{
+	int ret;
+
+	ret = pci_write_config_dword(s->pdev, off, val);
+	if (ret)
+		s->io_err = pcibios_err_to_errno(ret);
+}
+
+static u32 imc_busy_mask(struct imc_smbus *s)
+{
+	u32 busy = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imc_chans); i++)
+		if (imc_reg(s, imc_chans[i].stat) & STAT_BUSY)
+			busy |= BIT(i);
+
+	return busy;
+}
+
+static int imc_wait_engine_idle(struct imc_smbus *s)
+{
+	u32 busy;
+	int ret;
+
+	ret = read_poll_timeout(imc_busy_mask, busy, !busy || s->io_err,
+				IMC_POLL_US, IMC_IDLE_TIMEOUT_US, false, s);
+	if (ret)
+		dev_warn_ratelimited(s->dev,
+				     "engine busy on channel mask 0x%x\n", busy);
+
+	return ret;
+}
+
+static int imc_wait_go_clear(struct imc_smbus *s, const struct imc_chan *c)
+{
+	u32 val;
+
+	return read_poll_timeout(imc_reg, val, !(val & GO_BIT) || s->io_err,
+				 IMC_POLL_US, IMC_GO_TIMEOUT_US, false,
+				 s, c->data);
+}
+
+static int imc_wait_done(struct imc_smbus *s, const struct imc_chan *c,
+			 u32 *status)
+{
+	u32 val;
+	int ret;
+
+	ret = read_poll_timeout(imc_reg, val,
+				(!(val & STAT_BUSY) && (val & STAT_ANY_DONE)) ||
+				s->io_err,
+				IMC_POLL_US, IMC_DONE_TIMEOUT_US, false,
+				s, c->stat);
+	*status = val;
+
+	return ret;
+}
+
+static int imc_wait_transfer(struct imc_smbus *s, const struct imc_chan *c,
+			     u32 *status)
+{
+	u32 command;
+	int ret;
+
+	ret = imc_wait_go_clear(s, c);
+	if (ret)
+		*status = imc_reg(s, c->stat);
+	else
+		ret = imc_wait_done(s, c, status);
+	if (!ret)
+		return 0;
+	if (!(*status & STAT_BUSY) || (*status & STAT_ANY_DONE))
+		return ret;
+
+	command = imc_reg(s, c->data);
+	imc_set(s, c->data, command ^ COMMAND_TOGGLE);
+
+	ret = imc_wait_done(s, c, status);
+	if (ret)
+		dev_warn_ratelimited(s->dev,
+				     "ch%d recovery timed out (stat 0x%08x)\n",
+				     c->idx, *status);
+
+	return ret;
+}
+
+static int imc_check_status(struct imc_smbus *s, const struct imc_chan *c,
+			    u32 status, u32 expected, u8 addr, u8 reg)
+{
+	if (status & STAT_ERROR) {
+		dev_dbg(s->dev, "addr 0x%02x reg 0x%02x NACK (stat 0x%08x)\n",
+			addr, reg, status);
+		return -ENXIO;
+	}
+
+	/* Done bits are latched; only the bit for this operation is required. */
+	if (!(status & expected)) {
+		dev_warn_ratelimited(s->dev,
+				     "ch%d unexpected completion for addr 0x%02x reg 0x%02x (stat 0x%08x)\n",
+				     c->idx, addr, reg, status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * The done bits are latched and no way to clear them has been found, so a
+ * command that never reaches the register is indistinguishable from one that
+ * completed: STATUS still shows the previous DONE, the GO bit of the stale
+ * command word is already clear, and the caller would receive the previous
+ * transaction's data as valid.
+ *
+ * Read the command word back and require it to be the one just written.  The
+ * engine only ever clears GO, so that bit is the single permitted difference;
+ * anything else means the write did not land.  Checking the word rather than
+ * a status transition matters because two identical transfers in a row leave
+ * STATUS bit for bit the same.
+ */
+static bool imc_command_landed(u32 command, u32 readback)
+{
+	return !((command ^ readback) & ~GO_BIT);
+}
+
+/*
+ * Detect a second master.  Compare the command registers against what this
+ * driver left in them: for the channel it drove, only the bits it does not own;
+ * for the other channel, all of them.  A difference means firmware, a BMC or
+ * CLTT touched the engine while the transfer was in flight, so the result
+ * cannot be trusted.
+ */
+static int imc_check_interference(struct imc_smbus *s, const struct imc_chan *c,
+				  const struct imc_xfer_state *state)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imc_chans); i++) {
+		u32 mask = i == c->idx ? ~COMMAND_OUR_BITS : ~0U;
+		u32 expect = state->command[i] & COMMAND_KEEP_MASK;
+		u32 now = imc_reg(s, imc_chans[i].data);
+
+		if (!((now ^ expect) & mask))
+			continue;
+
+		dev_warn_ratelimited(s->dev,
+				     "ch%d command changed under us (0x%08x -> 0x%08x): another master is using the engine\n",
+				     i, expect, now);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static void imc_restore_xfer(struct imc_smbus *s,
+			     const struct imc_xfer_state *state)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imc_chans); i++) {
+		if (!state->restore[i])
+			continue;
+		/*
+		 * Mask GO: the saved word is only meant to put the previous
+		 * address, register and TSOD state back, never to re-arm a
+		 * transaction that was already in flight when we found it.
+		 */
+		imc_set(s, imc_chans[i].data, state->command[i] & ~GO_BIT);
+	}
+}
+
+static int imc_prepare_xfer(struct imc_smbus *s, const struct imc_chan *c,
+			    struct imc_xfer_state *state)
+{
+	int i, ret;
+
+	ret = imc_wait_engine_idle(s);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(imc_chans); i++) {
+		state->command[i] = imc_reg(s, imc_chans[i].data);
+		state->restore[i] = i == c->idx ||
+				    (state->command[i] & TSOD_ACTIVE_BIT);
+		if (!(state->command[i] & TSOD_ACTIVE_BIT))
+			continue;
+
+		imc_set(s, imc_chans[i].data,
+			state->command[i] & COMMAND_KEEP_MASK);
+		ret = imc_wait_go_clear(s, &imc_chans[i]);
+		if (ret) {
+			imc_restore_xfer(s, state);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int imc_access(struct imc_smbus *s, const struct imc_chan *c, u8 addr,
+		      u8 reg, char read_write, int size, u16 *value)
+{
+	struct imc_xfer_state state = {};
+	u32 command, expected, raw, readback, status = 0;
+	int ret;
+
+	ret = imc_prepare_xfer(s, c, &state);
+	if (ret)
+		return ret;
+
+	command = COMMAND_PREFIX | ((u32)addr << 8) | reg;
+	if (size == I2C_SMBUS_WORD_DATA)
+		command |= WORD_BIT;
+	else if (size == I2C_SMBUS_BYTE)
+		command |= PNTR_SEL_BIT;
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		raw = size == I2C_SMBUS_WORD_DATA ? swab16(*value) : *value;
+		imc_set(s, c->ctrl, raw << 16);
+		command |= WRITE_OPERATION;
+	}
+
+	imc_set(s, c->data, command);
+	readback = imc_reg(s, c->data);
+	if (!imc_command_landed(command, readback)) {
+		dev_warn_ratelimited(s->dev,
+				     "ch%d command 0x%08x did not reach the register (read back 0x%08x)\n",
+				     c->idx, command, readback);
+		ret = -EIO;
+		goto restore_command;
+	}
+
+	ret = imc_wait_transfer(s, c, &status);
+	if (ret)
+		goto restore_command;
+
+	expected = read_write == I2C_SMBUS_WRITE ?
+		   STAT_WRITE_DONE : STAT_READ_DONE;
+	ret = imc_check_status(s, c, status, expected, addr, reg);
+	if (ret)
+		goto restore_command;
+
+	ret = imc_check_interference(s, c, &state);
+	if (ret)
+		goto restore_command;
+
+	if (read_write == I2C_SMBUS_READ) {
+		raw = imc_reg(s, c->ctrl);
+		*value = size == I2C_SMBUS_WORD_DATA ?
+			 swab16(raw & 0xffff) : raw & 0xff;
+	}
+
+restore_command:
+	imc_restore_xfer(s, &state);
+
+	return ret;
+}
+
+/*
+ * Standard SMBus transfer callback.  The per-channel imc_chan is stashed in the
+ * adapter's algo_data.  The command word carries the 7-bit address, so
+ * SPD EEPROMs (0x50-0x57) are reachable on each channel.  BYTE, BYTE_DATA and
+ * WORD_DATA are supported; larger transfers would need the engine's block
+ * primitives, which are not used by the devices on this bus.
+ */
+static s32 imc_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+			  unsigned short flags, char read_write, u8 command,
+			  int size, union i2c_smbus_data *data)
+{
+	struct imc_smbus *s = i2c_get_adapdata(adap);
+	const struct imc_chan *c = adap->algo_data;
+	u16 val = 0;
+	u8 reg;
+	int ret;
+
+	if (flags & I2C_M_TEN)
+		return -EAFNOSUPPORT;
+	if (addr > 0x7f)
+		return -EINVAL;
+
+	if (size != I2C_SMBUS_BYTE && size != I2C_SMBUS_BYTE_DATA &&
+	    size != I2C_SMBUS_WORD_DATA)
+		return -EOPNOTSUPP;
+	if (read_write != I2C_SMBUS_READ && read_write != I2C_SMBUS_WRITE)
+		return -EINVAL;
+
+	/*
+	 * BYTE puts no register on the bus.  For a write the command parameter
+	 * carries the data byte instead, and data is NULL.
+	 */
+	reg = size == I2C_SMBUS_BYTE ? 0 : command;
+
+	mutex_lock(&s->lock);
+	s->io_err = 0;
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		switch (size) {
+		case I2C_SMBUS_BYTE:
+			val = command;
+			dev_dbg(s->dev, "ch%d W addr=%02x val=%02x (send byte)\n",
+				c->idx, addr, val);
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			val = data->word;
+			dev_dbg(s->dev, "ch%d W addr=%02x reg=%02x val=%04x\n",
+				c->idx, addr, reg, val);
+			break;
+		default:
+			val = data->byte;
+			dev_dbg(s->dev, "ch%d W addr=%02x reg=%02x val=%02x\n",
+				c->idx, addr, reg, val);
+			break;
+		}
+		ret = imc_access(s, c, addr, reg, read_write, size, &val);
+	} else {
+		ret = imc_access(s, c, addr, reg, read_write, size, &val);
+		switch (size) {
+		case I2C_SMBUS_BYTE:
+			if (!ret)
+				data->byte = val;
+			dev_dbg(s->dev, "ch%d R addr=%02x -> %02x (receive byte, ret %d)\n",
+				c->idx, addr, val, ret);
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			if (!ret)
+				data->word = val;
+			dev_dbg(s->dev, "ch%d R addr=%02x reg=%02x -> %04x (ret %d)\n",
+				c->idx, addr, reg, val, ret);
+			break;
+		default:
+			if (!ret)
+				data->byte = val;
+			dev_dbg(s->dev, "ch%d R addr=%02x reg=%02x -> %02x (ret %d)\n",
+				c->idx, addr, reg, val, ret);
+			break;
+		}
+	}
+
+	/*
+	 * A config-space failure invalidates whatever the transaction logic
+	 * concluded, so it wins over any other result.
+	 */
+	if (s->io_err) {
+		dev_warn_ratelimited(s->dev, "config access failed: %d\n",
+				     s->io_err);
+		ret = s->io_err;
+	}
+	mutex_unlock(&s->lock);
+
+	return ret;
+}
+
+static u32 imc_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+	       I2C_FUNC_SMBUS_WORD_DATA;
+}
+
+static const struct i2c_algorithm imc_algo = {
+	.smbus_xfer	= imc_smbus_xfer,
+	.functionality	= imc_func,
+};
+
+static int imc_suspend(struct device *dev)
+{
+	struct imc_smbus *s = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(s->adap); i++)
+		i2c_mark_adapter_suspended(&s->adap[i]);
+
+	return 0;
+}
+
+static int imc_resume(struct device *dev)
+{
+	struct imc_smbus *s = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(s->adap); i++)
+		i2c_mark_adapter_resumed(&s->adap[i]);
+
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(imc_pm_ops, imc_suspend, imc_resume);
+
+/*
+ * Refuse to share the engine with the memory controller's own thermal
+ * throttling.  SMBCNTL.TSOD_POLL_EN tells us directly whether the iMC is
+ * issuing SMBus transactions of its own; Intel documents that SPD command
+ * access and TSOD polling are mutually exclusive, so a set bit means the
+ * engine is not ours to drive.  This does not cover SMM or a BMC, which
+ * remain the reason for the allow_unsafe_access gate.
+ */
+static int imc_check_firmware_polling(struct pci_dev *pdev)
+{
+	struct pci_dev *imc = NULL;
+	unsigned int found = 0;
+	int i;
+
+	while ((imc = pci_get_device(PCI_VENDOR_ID_INTEL, IMC_CHANNEL_DEVICE,
+				     imc))) {
+		found++;
+		for (i = 0; i < ARRAY_SIZE(imc_chans); i++) {
+			u32 cntl;
+
+			if (pci_read_config_dword(imc, IMC_SMBCNTL(i), &cntl)) {
+				dev_warn(&pdev->dev,
+					 "%s ch%d SMBCNTL unreadable; cannot verify that TSOD polling is disabled\n",
+					 pci_name(imc), i);
+				continue;
+			}
+
+			if (cntl & SMBCNTL_TSOD_POLL_EN) {
+				dev_err(&pdev->dev,
+					"%s ch%d has TSOD polling enabled (SMBCNTL 0x%08x); the memory controller is using the engine\n",
+					pci_name(imc), i, cntl);
+				pci_dev_put(imc);
+				return -EBUSY;
+			}
+
+			dev_dbg(&pdev->dev,
+				"%s ch%d SMBCNTL 0x%08x, TSOD present mask 0x%02lx\n",
+				pci_name(imc), i, cntl,
+				cntl & SMBCNTL_TSOD_PRESENT);
+		}
+	}
+
+	if (!found)
+		dev_warn(&pdev->dev,
+			 "no iMC channel function found; cannot verify that TSOD polling is disabled\n");
+
+	return 0;
+}
+
+static int imc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct imc_smbus *s;
+	int ret, i;
+
+	if (!allow_unsafe_access) {
+		dev_info(&pdev->dev,
+			 "firmware/SMM arbitration is unknown; set allow_unsafe_access=1 to bind\n");
+		return -ENODEV;
+	}
+
+	ret = imc_check_firmware_polling(pdev);
+	if (ret)
+		return ret;
+
+	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	/*
+	 * No pci_enable_device(): the driver uses no BAR, no interrupt and no
+	 * DMA.  The engine is reached entirely through config space, which does
+	 * not require the function's memory or I/O decoding to be enabled.
+	 */
+	s->pdev = pdev;
+	s->dev = &pdev->dev;
+	pci_set_drvdata(pdev, s);
+	ret = devm_mutex_init(&pdev->dev, &s->lock);
+	if (ret)
+		return ret;
+
+	/*
+	 * Lifetime safety: the I2C core guarantees that smbus_xfer callbacks
+	 * are not invoked after i2c_del_adapter() returns. Since we use
+	 * devm_i2c_add_adapter(), the adapter is automatically removed on
+	 * driver detach, and no concurrent xfer can be in flight at that point.
+	 */
+	for (i = 0; i < ARRAY_SIZE(s->adap); i++) {
+		struct i2c_adapter *a = &s->adap[i];
+
+		a->owner     = THIS_MODULE;
+		a->algo      = &imc_algo;
+		a->algo_data = (void *)&imc_chans[i];
+		a->dev.parent = &pdev->dev;
+		/*
+		 * One retry: interference from another master is reported as
+		 * -EAGAIN and is usually over by the next attempt.
+		 */
+		a->retries = 1;
+		i2c_set_adapdata(a, s);
+		snprintf(a->name, sizeof(a->name),
+			 "iMC SMBus Skylake-X channel %d", i);
+
+		ret = devm_i2c_add_adapter(&pdev->dev, a);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"i2c_add_adapter ch%d failed: %d\n", i, ret);
+			return ret;
+		}
+
+		/*
+		 * Instantiate the SPD EEPROMs the same way the other SMBus
+		 * host drivers do.  This counts the populated slots from DMI
+		 * and probes 0x50 upwards, so no client is created for an
+		 * address that does not answer and userspace keeps the ones
+		 * that stay empty.  Each channel carries half the DIMMs, and
+		 * the scan is per adapter, so each finds its own.
+		 *
+		 * The write_disable variant: this part is DDR4 only, where the
+		 * two differ in nothing (the distinction gates spd5118 on
+		 * DDR5).  Where they are equivalent, the one that does not
+		 * suggest this driver enables SPD writes is the better name to
+		 * leave in a memory-bus driver.
+		 */
+		i2c_register_spd_write_disable(a);
+	}
+
+	dev_dbg(&pdev->dev, "registered 2 SMBus channels\n");
+	return 0;
+}
+
+static const struct pci_device_id imc_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCU_DEVICE) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, imc_pci_ids);
+
+/*
+ * All resources (mutex, i2c adapters) are devm-managed and are released
+ * automatically after probe returns or during device unbinding, so no .remove
+ * callback is needed.  The register state is deliberately left as-is on
+ * unbind: the engine carries no driver-private latched state that needs
+ * teardown, and the SMBus controls we drive are side-band registers the rest
+ * of the kernel does not touch.
+ */
+static struct pci_driver imc_driver = {
+	.name     = "i2c-imc-skylake",
+	.id_table = imc_pci_ids,
+	.probe    = imc_pci_probe,
+	.driver.pm = pm_sleep_ptr(&imc_pm_ops),
+};
+module_pci_driver(imc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simone Chifari");
+MODULE_DESCRIPTION("Intel Skylake-X iMC SMBus I2C adapter");
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-28 12:24 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28 12:24 [PATCH v3 0/1] i2c: imc-skylake: add Intel Skylake-X iMC SMBus adapter Simone Chifari
2026-07-28 12:24 ` [PATCH v3 1/1] " Simone Chifari

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox