[RFC PATCH 0/4] espi: introduce eSPI bus framework

Krishnamoorthi M posted 4 patches 1 month, 4 weeks ago
Documentation/driver-api/espi.rst  | 213 +++++++++++++
Documentation/driver-api/index.rst |   1 +
MAINTAINERS                        |   8 +
drivers/Kconfig                    |   2 +
drivers/Makefile                   |   1 +
drivers/espi/Kconfig               |  41 +++
drivers/espi/Makefile              |   3 +
drivers/espi/espi-amd.c            | 453 ++++++++++++++++++++++++++
drivers/espi/espi-amd.h            | 126 ++++++++
drivers/espi/espi-core.c           | 493 +++++++++++++++++++++++++++++
drivers/espi/espi-slave.c          | 177 +++++++++++
include/linux/espi/espi.h          | 345 ++++++++++++++++++++
12 files changed, 1863 insertions(+)
create mode 100644 Documentation/driver-api/espi.rst
create mode 100644 drivers/espi/Kconfig
create mode 100644 drivers/espi/Makefile
create mode 100644 drivers/espi/espi-amd.c
create mode 100644 drivers/espi/espi-amd.h
create mode 100644 drivers/espi/espi-core.c
create mode 100644 drivers/espi/espi-slave.c
create mode 100644 include/linux/espi/espi.h
[RFC PATCH 0/4] espi: introduce eSPI bus framework
Posted by Krishnamoorthi M 1 month, 4 weeks ago
This RFC proposes a new eSPI (Enhanced Serial Peripheral Interface) bus
subsystem for Linux.

Background
==========

I previously posted to the list asking whether extending the existing SPI
subsystem or introducing a new bus type was the preferred direction for eSPI
support [1]. This series represents the new-bus-type approach, implemented
and validated on AMD hardware.

eSPI is an Intel-defined protocol replacing the legacy LPC bus. Unlike SPI,
eSPI is capability-negotiated: the controller and target exchange capability
registers at link bring-up to agree on I/O mode, clock frequency and CRC.
Traffic is carried over four logically independent channels on a single
shared physical link, and the target signals upstream data availability
asynchronously via an ALERT# pin rather than chip-select assertion.
These characteristics do not fit the synchronous, single-channel, transfer-
oriented SPI model, so a dedicated bus type is proposed.

Channel Model
=============

The four eSPI channels each serve a distinct purpose:

  - Peripheral channel: carries host I/O and memory cycles to/from the
    target, replacing the LPC I/O and memory cycles used by devices such
    as EC and BMC firmware.

  - Virtual Wire channel: transfers logical signal state (power sequencing
    signals, SMI#, SCI#, IRQs) as indexed wire groups, replacing the
    physical LPC sideband signals.

  - OOB channel: tunnels SMBus/I2C messages between the host and an
    out-of-band processor on the target, enabling management traffic
    independent of the host OS.

  - Flash Access channel: provides access to a SPI flash device attached
    to the target, allowing the host to share a single flash with the
    target firmware.

Design Overview
===============

The framework follows the established Linux bus/device/driver model:

  - struct espi_controller: the host controller, registered with
    espi_controller_register(). Capabilities are negotiated at runtime
    and stored in struct espi_capabilities. Each controller is assigned
    a bus number from an XArray allocator. Read-only sysfs attributes
    (supported_channels, channel_enabled, io_mode, max_freq_mhz) expose
    the negotiated link state to userspace.

  - struct espi_device: a target on the bus, identified by its Chip
    Select# index (cs field). The eSPI spec allows one controller to
    drive multiple targets via separate CS# pins; ctrl->max_targets
    advertises the hardware limit and cs is range-checked at device
    creation. Devices are matched to drivers by modalias.

  - struct espi_controller_ops: an all-optional hardware callback table.
    The core returns -EOPNOTSUPP for unimplemented ops, allowing
    incremental controller driver development across patch series.

  - A per-controller blocking notifier chain delivers hardware events
    (Virtual Wire changes, OOB messages, channel state transitions,
    In-Band Reset) to slave drivers from process context. A blocking
    notifier is used rather than a raw notifier because slave driver
    callbacks may sleep, for example to issue follow-up configuration
    commands over the bus.

  - A single per-controller mutex serialises all channel operations.
    This is intentional: eSPI has one shared physical link and only one
    downstream transaction can be in flight at a time regardless of the
    logical channel, consistent with how struct spi_controller is modelled.
    Because the mutex is a sleeping lock, all ops must be called from
    process context; the alert handler is therefore registered with
    IRQF_ONESHOT and dispatches from a threaded IRQ.

Alert Mechanism
===============

When the target has upstream data pending it asserts ALERT# (dedicated
pin or in-band on I/O[1]). The controller's hard-IRQ handler acknowledges
the interrupt and defers processing to a threaded IRQ, which calls
espi_handle_alert(). This dispatches to ops->handle_alert WITHOUT holding
ctrl->lock, so that the driver callback can call espi_notify_event() to
deliver the appropriate ESPI_EVENT_* to registered slave driver notifiers
without deadlocking: notifier callbacks may in turn call channel APIs
that also acquire ctrl->lock. The driver is responsible for acquiring
ctrl->lock around any register accesses that require serialisation with
the channel API. The alert path implementation is deferred to follow-on
patches; the hook points are in place in this series.

Scope of this RFC
=================

This series covers the framework foundation and the AMD FCH controller
driver (ACPI HID: AMDI0070). It intentionally limits scope to the
channel-independent layer: capability discovery, GET/SET_CONFIGURATION
and In-Band Reset. Channel-specific operations (Peripheral I/O and
memory, Virtual Wire, OOB, Flash Access) and the alert/interrupt path
are declared in the API but their implementations are deferred to
follow-on patches, to be posted once the framework design is reviewed.

Testing
=======

The series has been validated on AMD hardware (AMD FCH, AMDI0070) using
an internal test slave driver that binds as an eSPI slave device and
exposes a sysfs command interface. The following scenarios were
exercised:

  - GET_CONFIGURATION on the General Capabilities register (0x08):
    verified correct decoding of I/O mode, operating frequency, CRC,
    Alert mode, Max WAIT STATE, and supported channels.

  - SET_CONFIGURATION on the General Capabilities register: verified
    successful negotiation of I/O mode (single/dual/quad) and operating
    frequency (16/33/66 MHz), and confirmed the host-side register is
    updated to match the negotiated parameters.

  - In-Band Reset: verified the reset completes successfully and the
    host controller registers are restored to match the target's
    post-reset state (16 MHz / single I/O).

Known Limitations / Future Work
================================

  - No Device Tree bindings in this series. The AMD controller uses
    ACPI enumeration. DT support will follow.

  - Slave device enumeration is manual (espi_new_device). ACPI/DT-based
    enumeration will be added in a subsequent patch.

  - Channel ops (Peripheral, VWire, OOB, Flash) and alert/interrupt
    handling are deferred to follow-on patches.

Feedback Requested
==================

  1. We chose a dedicated bus_type for the reasons described above
     (capability negotiation, four independent channels, asynchronous
     ALERT#). Does the community agree this is the right direction, or
     is there a strong preference to extend the SPI subsystem instead?
  2. Is the blocking notifier chain the right mechanism for event
     delivery to slave drivers?
  3. Any concerns with the ops table design or the -EOPNOTSUPP fallback?
  4. Naming and structure of the public API in include/linux/espi/espi.h.

References
==========

[1] https://lore.kernel.org/lkml/9548669c-7d3c-4053-b28b-c82490c0c2b8@amd.com/T/#u
[2] Intel Enhanced Serial Peripheral Interface (eSPI) Interface Base
    Specification

Krishnamoorthi M (4):
  espi: add core bus framework
  espi: add slave device model and event notification
  Documentation: espi: add subsystem overview and MAINTAINERS entry
  espi: amd: add AMD eSPI controller driver

 Documentation/driver-api/espi.rst  | 213 +++++++++++++
 Documentation/driver-api/index.rst |   1 +
 MAINTAINERS                        |   8 +
 drivers/Kconfig                    |   2 +
 drivers/Makefile                   |   1 +
 drivers/espi/Kconfig               |  41 +++
 drivers/espi/Makefile              |   3 +
 drivers/espi/espi-amd.c            | 453 ++++++++++++++++++++++++++
 drivers/espi/espi-amd.h            | 126 ++++++++
 drivers/espi/espi-core.c           | 493 +++++++++++++++++++++++++++++
 drivers/espi/espi-slave.c          | 177 +++++++++++
 include/linux/espi/espi.h          | 345 ++++++++++++++++++++
 12 files changed, 1863 insertions(+)
 create mode 100644 Documentation/driver-api/espi.rst
 create mode 100644 drivers/espi/Kconfig
 create mode 100644 drivers/espi/Makefile
 create mode 100644 drivers/espi/espi-amd.c
 create mode 100644 drivers/espi/espi-amd.h
 create mode 100644 drivers/espi/espi-core.c
 create mode 100644 drivers/espi/espi-slave.c
 create mode 100644 include/linux/espi/espi.h

-- 
2.34.1
Re: [RFC PATCH 0/4] espi: introduce eSPI bus framework
Posted by Greg KH 1 month, 4 weeks ago
On Tue, Aug 04, 2026 at 05:22:55PM +0530, Krishnamoorthi M wrote:
> Feedback Requested
> ==================
> 
>   1. We chose a dedicated bus_type for the reasons described above
>      (capability negotiation, four independent channels, asynchronous
>      ALERT#). Does the community agree this is the right direction, or
>      is there a strong preference to extend the SPI subsystem instead?

That's up to the SPI maintainers and developers...

>   2. Is the blocking notifier chain the right mechanism for event
>      delivery to slave drivers?

Notifier chains are almost never the correct solution, especially for
real data you wish to send to devices/drivers.  Just use a real
callback function you have to register for, and a workqueue, or
something like that.  Ideally just use the process context of the thread
that created the data in the first place, why can't something simple
work like that?

>   3. Any concerns with the ops table design or the -EOPNOTSUPP fallback?
>   4. Naming and structure of the public API in include/linux/espi/espi.h.

What specifically are you asking for for this?  Do you have userspace
code you want to integrate, if so, does it work with this?  And where
does it live?

thanks,

greg k-h
Re: [RFC PATCH 0/4] espi: introduce eSPI bus framework
Posted by M, Krishnamoorthi 1 month, 3 weeks ago
Hi Greg,

On 8/4/2026 5:48 PM, Greg KH wrote:
> On Tue, Aug 04, 2026 at 05:22:55PM +0530, Krishnamoorthi M wrote:
>> Feedback Requested
>> ==================
>>
>>    1. We chose a dedicated bus_type for the reasons described above
>>       (capability negotiation, four independent channels, asynchronous
>>       ALERT#). Does the community agree this is the right direction, or
>>       is there a strong preference to extend the SPI subsystem instead?
> 
> That's up to the SPI maintainers and developers...
> 
>>    2. Is the blocking notifier chain the right mechanism for event
>>       delivery to slave drivers?
> 
> Notifier chains are almost never the correct solution, especially for
> real data you wish to send to devices/drivers.  Just use a real
> callback function you have to register for, and a workqueue, or
> something like that.  Ideally just use the process context of the thread
> that created the data in the first place, why can't something simple
> work like that?
> 

Thank you for the feedback. The notifier chain was chosen to support 
multiple slave drivers subscribing to events from a single controller. 
However, your concern is valid — it is not the right abstraction here. A 
cleaner approach is a typed per-device event callback on struct espi_driver:

void (*event)(struct espi_device *edev, struct espi_event *event);

When the controller decodes an ALERT#, it identifies the originating 
chip select# and calls the callback only on the driver bound to that 
device — no chain walking, no per-driver filtering, no untyped casts. 
The callback is invoked directly from the threaded IRQ context that 
decoded the event, keeping the delivery path simple as you suggested.

We will rework the event delivery along these lines in v2. Does this 
direction sound acceptable?

Thanks,
Krishna

>>    3. Any concerns with the ops table design or the -EOPNOTSUPP fallback?
>>    4. Naming and structure of the public API in include/linux/espi/espi.h.
> 
> What specifically are you asking for for this?  Do you have userspace
> code you want to integrate, if so, does it work with this?  And where
> does it live?
> 
> thanks,
> 
> greg k-h

Re: [RFC PATCH 0/4] espi: introduce eSPI bus framework
Posted by Andrew Jeffery 1 month, 4 weeks ago
Hi Greg, Krishnamoorthi,

YH Chung has been working on eSPI support for ASPEED's BMC SoCs, so
I've included them in the To line.

On Tue, 2026-08-04 at 14:18 +0200, Greg KH wrote:
> On Tue, Aug 04, 2026 at 05:22:55PM +0530, Krishnamoorthi M wrote:
> > Feedback Requested
> > ==================
> > 
> >   1. We chose a dedicated bus_type for the reasons described above
> >      (capability negotiation, four independent channels, asynchronous
> >      ALERT#). Does the community agree this is the right direction, or
> >      is there a strong preference to extend the SPI subsystem instead?
> 
> That's up to the SPI maintainers and developers...

There's concurrent discussion from YH regarding device-side eSPI
support in the thread ending here:

https://lore.kernel.org/all/KL1PR0601MB4276FA2C6347192CC45826E490ED2@KL1PR0601MB4276.apcprd06.prod.outlook.com/

So far it's arrived at a matching proposal for drivers/espi.

> 
> >   3. Any concerns with the ops table design or the -EOPNOTSUPP fallback?
> >   4. Naming and structure of the public API in include/linux/espi/espi.h.
> 
> What specifically are you asking for for this?  Do you have userspace
> code you want to integrate, if so, does it work with this?  And where
> does it live?

I've seen your follow-up realisation Greg, however, regarding
userspace, the thread above suggests that we should be able to back
existing subsystems (GPIO for VW, MCTP for OOB, MTD for some flash
functionality) onto eSPI to minimise eSPI-specific interfaces:

https://lore.kernel.org/all/KL1PR0601MB4276B5BE3B96C18E3A66AD709049A@KL1PR0601MB4276.apcprd06.prod.outlook.com/

That doesn't cover the peripheral channel, as that's dealt with in
hardware on the device side, but for the purpose of the controller the
devices on the peripheral channel should all be driven by the kernel
anyway.

Andrew
Re: [RFC PATCH 0/4] espi: introduce eSPI bus framework
Posted by M, Krishnamoorthi 1 month, 3 weeks ago
Hi Andrew,

On 8/5/2026 6:12 AM, Andrew Jeffery wrote:
> Hi Greg, Krishnamoorthi,
> 
> YH Chung has been working on eSPI support for ASPEED's BMC SoCs, so
> I've included them in the To line.
> 
> On Tue, 2026-08-04 at 14:18 +0200, Greg KH wrote:
>> On Tue, Aug 04, 2026 at 05:22:55PM +0530, Krishnamoorthi M wrote:
>>> Feedback Requested
>>> ==================
>>>
>>>    1. We chose a dedicated bus_type for the reasons described above
>>>       (capability negotiation, four independent channels, asynchronous
>>>       ALERT#). Does the community agree this is the right direction, or
>>>       is there a strong preference to extend the SPI subsystem instead?
>>
>> That's up to the SPI maintainers and developers...
> 
> There's concurrent discussion from YH regarding device-side eSPI
> support in the thread ending here:
> 
> https://lore.kernel.org/all/KL1PR0601MB4276FA2C6347192CC45826E490ED2@KL1PR0601MB4276.apcprd06.prod.outlook.com/
> 
> So far it's arrived at a matching proposal for drivers/espi.

Thank you for the introduction and for pointing to YH Chung's work. It 
is encouraging to see concurrent work arriving at a similar framework 
structure for drivers/espi — this gives us more confidence that the 
proposed design is on the right track.

> 
>>
>>>    3. Any concerns with the ops table design or the -EOPNOTSUPP fallback?
>>>    4. Naming and structure of the public API in include/linux/espi/espi.h.
>>
>> What specifically are you asking for for this?  Do you have userspace
>> code you want to integrate, if so, does it work with this?  And where
>> does it live?
> 
> I've seen your follow-up realisation Greg, however, regarding
> userspace, the thread above suggests that we should be able to back
> existing subsystems (GPIO for VW, MCTP for OOB, MTD for some flash
> functionality) onto eSPI to minimise eSPI-specific interfaces:
> 
> https://lore.kernel.org/all/KL1PR0601MB4276B5BE3B96C18E3A66AD709049A@KL1PR0601MB4276.apcprd06.prod.outlook.com/
> 
> That doesn't cover the peripheral channel, as that's dealt with in
> hardware on the device side, but for the purpose of the controller the
> devices on the peripheral channel should all be driven by the kernel
> anyway.
> 

I will go through YH Chung's complete thread on device-side eSPI support 
to understand the full picture. Reusing existing well-established kernel 
subsystems (GPIO for VWire, MCTP for OOB, MTD for Flash) to minimize 
eSPI-specific userspace interfaces is a sound direction.

YH Chung, would you be open to collaborating on the slave-side 
interfaces of the new eSPI framework? Happy to discuss further on the 
list or off-list to align on the design before the next revision.

Thanks,
Krishna

> Andrew

Re: [RFC PATCH 0/4] espi: introduce eSPI bus framework
Posted by Greg KH 1 month, 4 weeks ago
On Tue, Aug 04, 2026 at 02:18:42PM +0200, Greg KH wrote:
> On Tue, Aug 04, 2026 at 05:22:55PM +0530, Krishnamoorthi M wrote:
> >   4. Naming and structure of the public API in include/linux/espi/espi.h.
> 
> What specifically are you asking for for this?  Do you have userspace
> code you want to integrate, if so, does it work with this?  And where
> does it live?

Oops, sorry, I thought this was uapi stuff, nevermind...

greg "i need more coffee" k-h