[PATCH v5 2/6] spmi: apple: Validate FIFO state
Sasha Finkelstein
k at chaosmail.tech
Sat Aug 8 04:31:18 PDT 2026
From: Alba Mendez <me at alba.sh>
Check for data before reading the body of a reply, and check for
end of data afterwards.
Signed-off-by: Alba Mendez <me at alba.sh>
Reviewed-by: Janne Grunau <j at jannau.net>
Signed-off-by: Sasha Finkelstein <k at chaosmail.tech>
---
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
More information about the linux-arm-kernel
mailing list