[PATCH v3 14/15] ata: ahci: add shutdown helpers for AHCI controllers
Luca Lauro via B4 Relay <[email protected]> Sun, 02 Aug 2026 15:16:30 +0200
| Newsgroups | org.infradead.lists.barebox,org.kernel.feeds.b4-sent |
|---|---|
| Message-ID | <[email protected]> |
From: Luca Lauro <[email protected]> Introduce helper functions to stop the DMA engine and FIS receive engine before shutdown. These helpers mirror the libata shutdown sequence and ensure that no AHCI activity is in progress when the system powers off. Signed-off-by: Luca Lauro <[email protected]> --- drivers/ata/ahci.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a9a3f43f21..e9e73069c1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -21,6 +21,7 @@ #include <linux/sizes.h> #include <linux/pci.h> #include <clock.h> +#include <poweroff.h> #include "ahci.h" @@ -683,6 +684,65 @@ static int ahci_probe(struct device *dev) return ret; } +/* -------------------------------- */ +/* AHCI shutdown helpers */ +/* -------------------------------- */ + +/* Stop DMA engine (clear START, wait LIST_ON=0) */ +static int ahci_stop_engine(struct ahci_port *port) +{ + u32 cmd; + + cmd = ahci_port_read(port, PORT_CMD); + + /* Already stopped? */ + if (!(cmd & (PORT_CMD_START | PORT_CMD_LIST_ON))) + return 0; + + /* Clear START */ + cmd &= ~PORT_CMD_START; + ahci_port_write_f(port, PORT_CMD, cmd); + + /* Wait for LIST_ON to clear */ + return wait_on_timeout(500 * MSECOND, + !(ahci_port_read(port, PORT_CMD) & PORT_CMD_LIST_ON)); +} + +/* Stop FIS receive engine (clear FIS_RX, wait FIS_ON=0) */ +static int ahci_stop_fis_rx(struct ahci_port *port) +{ + u32 cmd; + + cmd = ahci_port_read(port, PORT_CMD); + cmd &= ~PORT_CMD_FIS_RX; + ahci_port_write_f(port, PORT_CMD, cmd); + + /* Wait for FIS_ON to clear */ + return wait_on_timeout(1000 * MSECOND, + !(ahci_port_read(port, PORT_CMD) & PORT_CMD_FIS_ON)); +} + +/* Stop all ports (libata_pci_shutdown_one equivalent) */ +static void __maybe_unused ahci_shutdown_host(struct ahci_device *ahci) +{ + int i, n_ports; + + n_ports = max_t(int, ahci->n_ports, fls(ahci->port_map)); + + for (i = 0; i < n_ports; i++) { + struct ahci_port *port = &ahci->ports[i]; + + if (!(ahci->port_map & (1 << i))) + continue; + + /* Stop DMA engine */ + ahci_stop_engine(port); + + /* Stop FIS receive engine */ + ahci_stop_fis_rx(port); + } +} + /* Issue FLUSH EXT + STANDBY IMMEDIATE */ static void ahci_port_shutdown(struct ahci_port *port) { -- 2.47.3