From: Krishnamoorthi M <krishnamoorthi.m@amd.com>
To: <linux-kernel@vger.kernel.org>
Cc: <gregkh@linuxfoundation.org>, <broonie@kernel.org>,
<linux-spi@vger.kernel.org>, <akshata.mukundshetty@amd.com>,
<bleung@chromium.org>, <groeck@chromium.org>,
<chrome-platform@lists.linux.dev>, <corbet@lwn.net>,
<linux-doc@vger.kernel.org>, <skhan@linuxfoundation.org>,
<andrew@codeconstruct.com.au>, <linux-aspeed@lists.ozlabs.org>,
<openbmc@lists.ozlabs.org>,
Krishnamoorthi M <krishnamoorthi.m@amd.com>
Subject: [RFC PATCH 3/4] Documentation: espi: add subsystem overview and MAINTAINERS entry
Date: Tue, 4 Aug 2026 17:22:58 +0530 [thread overview]
Message-ID: <20260804115259.4065638-4-krishnamoorthi.m@amd.com> (raw)
In-Reply-To: <20260804115259.4065638-1-krishnamoorthi.m@amd.com>
Add a driver-api overview of the eSPI subsystem and a MAINTAINERS entry
covering the subsystem files.
The document describes the architecture, how to write a controller driver
and a slave driver, the per-channel APIs (Peripheral, Virtual Wire, OOB,
Flash), the alert mechanism flow, and the event notification model. An
API Reference section renders kernel-doc from the exported symbols.
Signed-off-by: Krishnamoorthi M <krishnamoorthi.m@amd.com>
---
Documentation/driver-api/espi.rst | 213 +++++++++++++++++++++++++++++
Documentation/driver-api/index.rst | 1 +
MAINTAINERS | 8 ++
3 files changed, 222 insertions(+)
create mode 100644 Documentation/driver-api/espi.rst
diff --git a/Documentation/driver-api/espi.rst b/Documentation/driver-api/espi.rst
new file mode 100644
index 000000000000..60a3187edb05
--- /dev/null
+++ b/Documentation/driver-api/espi.rst
@@ -0,0 +1,213 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+===========================================
+eSPI (Enhanced Serial Peripheral Interface)
+===========================================
+
+Introduction
+============
+
+eSPI is a bus defined by Intel that replaces the legacy LPC bus. Unlike
+SPI it is a structured, capability-negotiated, message-oriented protocol
+with four logically independent channels (Peripheral, Virtual Wire, OOB,
+Flash) over a shared physical link, and asynchronous target-to-controller
+events, so it is modelled as its own bus type rather than an extension of
+the SPI subsystem.
+
+Architecture
+============
+
+* ``struct espi_controller`` - host controller, created with
+ espi_controller_alloc() and registered with espi_controller_register().
+ It is not itself a device on espi_bus_type.
+* ``struct espi_device`` - a target on the bus, matched to a
+ ``struct espi_driver`` via its modalias.
+* ``struct espi_controller_ops`` - the optional hardware-op table; the
+ channel API returns -EOPNOTSUPP for ops a controller does not provide.
+
+Writing a controller driver
+===========================
+
+A controller driver allocates and registers a controller from its
+``probe()`` function::
+
+ ctrl = espi_controller_alloc(&pdev->dev, sizeof(*priv));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ priv = espi_controller_get_devdata(ctrl);
+ ctrl->ops = &my_espi_ops;
+ ctrl->max_targets = 1;
+
+ /* populate ctrl->caps from hardware capability registers */
+ ctrl->caps.supported_channels = ESPI_CHANNEL_ALL;
+ ctrl->caps.max_freq_mhz = 33;
+ ctrl->caps.io_mode = ESPI_IO_MODE_SINGLE;
+
+ ret = espi_controller_register(ctrl);
+ if (ret)
+ goto err_put;
+
+After registration the controller calls espi_new_device() for each
+target enumerated from firmware (ACPI or device tree)::
+
+ struct espi_board_info info = {
+ .type = "my-ec",
+ .cs = 0,
+ };
+ edev = espi_new_device(ctrl, &info);
+
+On removal::
+
+ espi_remove_device(edev);
+ espi_controller_unregister(ctrl);
+ espi_controller_put(ctrl);
+
+Writing a slave driver
+======================
+
+A slave driver declares a device ID table and a ``struct espi_driver``::
+
+ static const struct espi_device_id my_ec_ids[] = {
+ { "my-ec", 0 },
+ { }
+ };
+ MODULE_DEVICE_TABLE(espi, my_ec_ids);
+
+ static int my_ec_probe(struct espi_device *edev)
+ {
+ /* register for hardware events */
+ nb->notifier_call = my_ec_event;
+ espi_register_notifier(edev->ctrl, nb);
+ return 0;
+ }
+
+ static void my_ec_remove(struct espi_device *edev)
+ {
+ espi_unregister_notifier(edev->ctrl, nb);
+ }
+
+ static struct espi_driver my_ec_driver = {
+ .driver = { .name = "my-ec" },
+ .id_table = my_ec_ids,
+ .probe = my_ec_probe,
+ .remove = my_ec_remove,
+ };
+ module_espi_driver(my_ec_driver);
+
+Channel-independent commands
+============================
+
+espi_get_configuration(), espi_set_configuration(), espi_inband_reset()
+and espi_get_status(). GET_STATUS is optional: controllers whose hardware
+does not implement the wire command leave .get_status unset.
+
+Capability negotiation and channel management
+=============================================
+
+At boot the controller driver reads the target's capability registers via
+espi_get_configuration(), negotiates link parameters (I/O mode, clock
+frequency, CRC) via espi_set_configuration(), then enables each channel
+with espi_enable_channel(). espi_channel_is_enabled() may be called at
+any time to query the current state. Channels may be disabled individually
+with espi_disable_channel(), for example before an in-band reset.
+
+Channel APIs
+============
+
+Peripheral channel
+------------------
+
+Carries I/O and memory cycles between the host and target endpoints.
+
+* espi_periph_io_read() / espi_periph_io_write() — 16-bit I/O port
+ access; ``width`` is the access size in bytes (1, 2, or 4).
+* espi_periph_mem_read() / espi_periph_mem_write() — 32-bit memory
+ mapped access.
+
+Virtual Wire channel
+--------------------
+
+Carries logical signal state (power sequencing, SMI#, SCI#, IRQs) as
+indexed wire groups. Each group carries up to four wire values with
+individual valid bits.
+
+* espi_vwire_get() — read a wire group from the target.
+* espi_vwire_put() — send a PUT_VIRTUAL_WIRE command to the target.
+ Named after the eSPI PUT_VW wire command, not a reference-count
+ release.
+
+Wire changes from the target generate an ``ESPI_EVENT_VWIRE_CHANGED``
+event delivered through the notifier chain.
+
+OOB channel
+-----------
+
+Tunnels SMBus/I2C messages between the host and target out-of-band
+processor (BMC, EC). Messages are exchanged as opaque byte buffers with
+a tag field for matching requests to responses.
+
+* espi_oob_send() / espi_oob_recv()
+
+Incoming OOB messages generate an ``ESPI_EVENT_OOB_RECEIVED`` event.
+
+Flash Access channel
+--------------------
+
+Provides access to a SPI flash device attached to the target. The target
+acts as a proxy for flash read, write, and erase operations.
+
+* espi_flash_read() / espi_flash_write() / espi_flash_erase()
+
+Alert mechanism
+===============
+
+When the target has upstream data pending it asserts ``ALERT#``. The
+controller's hard-IRQ handler acknowledges the interrupt and defers
+processing to a threaded IRQ or workqueue. From that process context the
+controller driver calls espi_handle_alert(), which acquires the
+controller lock and dispatches to ``ops->handle_alert``. The hardware
+callback reads the target's status register (GET_STATUS), identifies the
+pending channel, and calls espi_notify_event() to deliver the appropriate
+``ESPI_EVENT_*`` to all registered slave driver notifiers::
+
+ ALERT# asserted by target
+ |
+ v
+ hard-IRQ handler (controller driver)
+ |
+ v
+ threaded IRQ / workqueue
+ |
+ v
+ espi_handle_alert(ctrl) [espi-core.c]
+ |
+ v
+ ops->handle_alert(ctrl) [controller driver]
+ | reads GET_STATUS, decodes channel
+ v
+ espi_notify_event(ctrl, &event) [espi-slave.c]
+ |
+ v
+ slave driver notifier callback
+
+espi_handle_alert() must always be called from process context; it must
+never be called from a hard-IRQ handler.
+
+Events and concurrency
+======================
+
+Hardware events (Virtual Wire changes, OOB messages, Peripheral channel
+completions, channel state changes) are delivered through a per-controller
+blocking notifier chain (espi_register_notifier()/espi_notify_event()).
+Callbacks run in process context; controllers deliver events from a
+threaded IRQ or workqueue, never from hardirq and never while holding the
+controller lock.
+
+API Reference
+=============
+
+.. kernel-doc:: include/linux/espi/espi.h
+
+.. kernel-doc:: drivers/espi/espi-slave.c
+ :export:
diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst
index 6601a258690f..175ed0794a48 100644
--- a/Documentation/driver-api/index.rst
+++ b/Documentation/driver-api/index.rst
@@ -139,6 +139,7 @@ Subsystem-specific APIs
sm501
soundwire/index
spi
+ espi
surface_aggregator/index
switchtec
sync_file
diff --git a/MAINTAINERS b/MAINTAINERS
index e95fc6f2ddc6..c416326d14fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9705,6 +9705,14 @@ F: Documentation/devicetree/bindings/clock/eswin,eic7700-clock.yaml
F: drivers/clk/eswin/
F: include/dt-bindings/clock/eswin,eic7700-clock.h
+ESPI SUBSYSTEM
+M: Krishnamoorthi M <krishnamoorthi.m@amd.com>
+L: linux-kernel@vger.kernel.org
+S: Supported
+F: Documentation/driver-api/espi.rst
+F: drivers/espi/
+F: include/linux/espi/
+
ET131X NETWORK DRIVER
M: Mark Einon <mark.einon@gmail.com>
S: Odd Fixes
--
2.34.1
next prev parent reply other threads:[~2026-08-04 11:54 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 11:52 [RFC PATCH 0/4] espi: introduce eSPI bus framework Krishnamoorthi M
2026-08-04 11:52 ` [RFC PATCH 1/4] espi: add core " Krishnamoorthi M
2026-08-06 13:31 ` Uwe Kleine-König
2026-08-04 11:52 ` [RFC PATCH 2/4] espi: add slave device model and event notification Krishnamoorthi M
2026-08-04 11:52 ` Krishnamoorthi M [this message]
2026-08-04 16:39 ` [RFC PATCH 3/4] Documentation: espi: add subsystem overview and MAINTAINERS entry Randy Dunlap
2026-08-04 19:14 ` M, Krishnamoorthi
2026-08-04 11:52 ` [RFC PATCH 4/4] espi: amd: add AMD eSPI controller driver Krishnamoorthi M
2026-08-04 12:18 ` [RFC PATCH 0/4] espi: introduce eSPI bus framework Greg KH
2026-08-04 13:26 ` Greg KH
2026-08-05 0:42 ` Andrew Jeffery
2026-08-05 18:35 ` M, Krishnamoorthi
2026-08-05 10:14 ` M, Krishnamoorthi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260804115259.4065638-4-krishnamoorthi.m@amd.com \
--to=krishnamoorthi.m@amd.com \
--cc=akshata.mukundshetty@amd.com \
--cc=andrew@codeconstruct.com.au \
--cc=bleung@chromium.org \
--cc=broonie@kernel.org \
--cc=chrome-platform@lists.linux.dev \
--cc=corbet@lwn.net \
--cc=gregkh@linuxfoundation.org \
--cc=groeck@chromium.org \
--cc=linux-aspeed@lists.ozlabs.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-spi@vger.kernel.org \
--cc=openbmc@lists.ozlabs.org \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox