Linux Documentation
 help / color / mirror / Atom feed
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


  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