[PATCH v5 2/6] spmi: apple: Validate FIFO state

From: Sasha Finkelstein

Date: Sat Aug 08 2026 - 07:33:04 EST


From: Alba Mendez <me@xxxxxxx>

Check for data before reading the body of a reply, and check for
end of data afterwards.

Signed-off-by: Alba Mendez <me@xxxxxxx>
Reviewed-by: Janne Grunau <j@xxxxxxxxxx>
Signed-off-by: Sasha Finkelstein <k@xxxxxxxxxxxxxx>
---
drivers/spmi/spmi-apple-controller.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/drivers/spmi/spmi-apple-controller.c b/drivers/spmi/spmi-apple-controller.c
index 376cf682c43e..15721cb41d5c 100644
--- a/drivers/spmi/spmi-apple-controller.c
+++ b/drivers/spmi/spmi-apple-controller.c
@@ -21,7 +21,9 @@
#define SPMI_STATUS_REG 0
#define SPMI_CMD_REG 0x4
#define SPMI_RSP_REG 0x8
+#define SPMI_ACT_REG 0xa4

+#define SPMI_ACT_FIFO_FLUSH BIT(0)
#define SPMI_RX_FIFO_EMPTY BIT(24)

#define REG_POLL_INTERVAL_US 10000
@@ -29,6 +31,7 @@

struct apple_spmi {
void __iomem *regs;
+ bool prev_fail;
};

#define poll_reg(spmi, reg, val, cond) \
@@ -49,6 +52,7 @@ static int apple_spmi_wait_rx_not_empty(struct spmi_controller *ctrl)

ret = poll_reg(spmi, SPMI_STATUS_REG, status, !(status & SPMI_RX_FIFO_EMPTY));
if (ret) {
+ spmi->prev_fail = true;
dev_err(&ctrl->dev,
"failed to wait for RX FIFO not empty\n");
return ret;
@@ -67,6 +71,11 @@ static int spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
u8 i;
int ret;

+ if (spmi->prev_fail) {
+ writel(SPMI_ACT_FIFO_FLUSH, spmi->regs + SPMI_ACT_REG);
+ spmi->prev_fail = false;
+ }
+
writel(spmi_cmd, spmi->regs + SPMI_CMD_REG);

ret = apple_spmi_wait_rx_not_empty(ctrl);
@@ -78,6 +87,12 @@ static int spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,

/* Read SPMI data reply */
while (len_read < len) {
+ if (readl(spmi->regs + SPMI_STATUS_REG) & SPMI_RX_FIFO_EMPTY) {
+ spmi->prev_fail = true;
+ dev_err_ratelimited(&ctrl->dev,
+ "FIFO lacks reply data, controller stuck?\n");
+ return -EIO;
+ }
rsp = readl(spmi->regs + SPMI_RSP_REG);
i = 0;
while ((len_read < len) && (i < 4)) {
@@ -86,6 +101,11 @@ static int spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
}
}

+ if (!(readl(spmi->regs + SPMI_STATUS_REG) & SPMI_RX_FIFO_EMPTY)) {
+ dev_warn(&ctrl->dev, "FIFO has extra data\n");
+ spmi->prev_fail = true;
+ }
+
return 0;
}

@@ -97,6 +117,11 @@ static int spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
size_t i = 0, j;
int ret;

+ if (spmi->prev_fail) {
+ writel(SPMI_ACT_FIFO_FLUSH, spmi->regs + SPMI_ACT_REG);
+ spmi->prev_fail = false;
+ }
+
writel(spmi_cmd, spmi->regs + SPMI_CMD_REG);

while (i < len) {
@@ -115,6 +140,11 @@ static int spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
/* Discard */
readl(spmi->regs + SPMI_RSP_REG);

+ if (!(readl(spmi->regs + SPMI_STATUS_REG) & SPMI_RX_FIFO_EMPTY)) {
+ dev_warn(&ctrl->dev, "FIFO has extra data\n");
+ spmi->prev_fail = true;
+ }
+
return 0;
}


--
2.55.0