drivers/spi/spi-hisi-kunpeng.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
The hisi_spi_flush_fifo()'s inner while loop that lacks any timeout
mechanism. Maybe the hardware never becomes empty, the loop will spin
forever, causing the CPU to hang.
Fix this by adding a inner_limit based on loops_per_jiffy. The inner loop
now exits after approximately one jiffy if the FIFO remains non-empty, logs
a ratelimited warning, and breaks out of the outer loop. Additionally, add
a cpu_relax() inside the busy loop to improve power efficiency.
Also add a ratelimited warning when the outer limit expires, to aid in
debugging hardware stalls.
Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs")
Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn>
---
drivers/spi/spi-hisi-kunpeng.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c
index 216a0a91fc47..b3359ac3a366 100644
--- a/drivers/spi/spi-hisi-kunpeng.c
+++ b/drivers/spi/spi-hisi-kunpeng.c
@@ -196,9 +196,22 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs)
unsigned long limit = loops_per_jiffy << 1;
do {
- while (hisi_spi_rx_not_empty(hs))
+ unsigned long inner_limit = loops_per_jiffy;
+
+ while (hisi_spi_rx_not_empty(hs) && inner_limit--) {
readl(hs->regs + HISI_SPI_DOUT);
+ cpu_relax();
+ }
+
+ if (!inner_limit) {
+ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n");
+ break;
+ }
+
} while (hisi_spi_busy(hs) && limit--);
+
+ if (!limit)
+ dev_warn_ratelimited(hs->dev, "SPI busy timeout\n");
}
/* Disable the controller and all interrupts */
--
2.25.1
Hi Pei,
kernel test robot noticed the following build warnings:
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Pei-Xiao/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi_spi_flush_fifo/20260318-211321
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link: https://lore.kernel.org/r/d50f1f46b2ee2bba05de9e2d4199353b545194e3.1773820898.git.xiaopei01%40kylinos.cn
patch subject: [PATCH] spi: hisi-kunpeng: prevent infinite while() loop in hisi_spi_flush_fifo
config: s390-randconfig-r072-20260319 (https://download.01.org/0day-ci/archive/20260319/202603192159.S0PIjhlg-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 4abb927bacf37f18f6359a41639a6d1b3bffffb5)
smatch: v0.5.0-9004-gb810ac53
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202603192159.S0PIjhlg-lkp@intel.com/
smatch warnings:
drivers/spi/spi-hisi-kunpeng.c:206 hisi_spi_flush_fifo() warn: should this be 'inner_limit == -1'
vim +206 drivers/spi/spi-hisi-kunpeng.c
c770d8631e1810 Jay Fang 2021-03-27 193
c770d8631e1810 Jay Fang 2021-03-27 194 static void hisi_spi_flush_fifo(struct hisi_spi *hs)
c770d8631e1810 Jay Fang 2021-03-27 195 {
c770d8631e1810 Jay Fang 2021-03-27 196 unsigned long limit = loops_per_jiffy << 1;
c770d8631e1810 Jay Fang 2021-03-27 197
c770d8631e1810 Jay Fang 2021-03-27 198 do {
e8821f559fed86 Pei Xiao 2026-03-18 199 unsigned long inner_limit = loops_per_jiffy;
e8821f559fed86 Pei Xiao 2026-03-18 200
e8821f559fed86 Pei Xiao 2026-03-18 201 while (hisi_spi_rx_not_empty(hs) && inner_limit--) {
c770d8631e1810 Jay Fang 2021-03-27 202 readl(hs->regs + HISI_SPI_DOUT);
e8821f559fed86 Pei Xiao 2026-03-18 203 cpu_relax();
e8821f559fed86 Pei Xiao 2026-03-18 204 }
e8821f559fed86 Pei Xiao 2026-03-18 205
e8821f559fed86 Pei Xiao 2026-03-18 @206 if (!inner_limit) {
This test is wrong. Maybe change inner_limit-- to
--inner_limit.
e8821f559fed86 Pei Xiao 2026-03-18 207 dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n");
e8821f559fed86 Pei Xiao 2026-03-18 208 break;
e8821f559fed86 Pei Xiao 2026-03-18 209 }
e8821f559fed86 Pei Xiao 2026-03-18 210
c770d8631e1810 Jay Fang 2021-03-27 211 } while (hisi_spi_busy(hs) && limit--);
e8821f559fed86 Pei Xiao 2026-03-18 212
e8821f559fed86 Pei Xiao 2026-03-18 213 if (!limit)
e8821f559fed86 Pei Xiao 2026-03-18 214 dev_warn_ratelimited(hs->dev, "SPI busy timeout\n");
c770d8631e1810 Jay Fang 2021-03-27 215 }
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On Wed, Mar 18, 2026 at 04:02:43PM +0800, Pei Xiao wrote: > Also add a ratelimited warning when the outer limit expires, to aid in > debugging hardware stalls. That's a bit of a separate change, should really have been a separate patch... > } while (hisi_spi_busy(hs) && limit--); > + > + if (!limit) > + dev_warn_ratelimited(hs->dev, "SPI busy timeout\n"); > } The limit check is a postdecrement so we read the value, compare it to 0, subtract 1 and then break out of the loop - that means that when we come out of the loop the value of limit is non-zero again and the warning won't trigger.
在 2026/3/18 21:17, Mark Brown 写道: > On Wed, Mar 18, 2026 at 04:02:43PM +0800, Pei Xiao wrote: > >> Also add a ratelimited warning when the outer limit expires, to aid in >> debugging hardware stalls. > That's a bit of a separate change, should really have been a separate > patch... ok. >> } while (hisi_spi_busy(hs) && limit--); >> + >> + if (!limit) >> + dev_warn_ratelimited(hs->dev, "SPI busy timeout\n"); >> } > The limit check is a postdecrement so we read the value, compare it to > 0, subtract 1 and then break out of the loop - that means that when we > come out of the loop the value of limit is non-zero again and the > warning won't trigger. yes, my fault! I will use '--limit'. Thanks for your review and response! Pei.
© 2016 - 2026 Red Hat, Inc.