mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/5] spi: fix division by zero with a zero transfer speed
@ 2026-11-06 15:47 shao.mingyin
  2026-11-06 15:47 ` [PATCH 1/5] spi: sifive: fix division by zero in clock divisor calculation shao.mingyin
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: shao.mingyin @ 2026-11-06 15:47 UTC (permalink / raw)
  To: broonie, linux-spi
  Cc: linux-kernel, linux-riscv, pjw, samuel.holland, william.zhang,
	kursad.oney, jonas.gorski, bcm-kernel-feedback-list, anand.gore,
	florian.fainelli, rafal, linux-arm-kernel, sven, j, neal, asahi,
	ryan.wanner, nicolas.ferre, alexandre.belloni, claudiu.beznea

Five SPI controller drivers compute a clock divider from the transfer
speed without checking that it is non-zero.  A SPI device whose
max_speed_hz is zero (a DT node without spi-max-frequency, or a device
created through the spidev sysfs new_device interface without a speed)
therefore reaches the division with speed_hz == 0.  The SPI core clamps
such a device to the controller limit only when host->max_speed_hz is
set, and none of these five drivers sets it.

The series is organized by driver and is independent patch-by-patch;
each patch can be applied and reviewed on its own, and taking a subset
is fine:

  1/5 spi: sifive: fix division by zero in clock divisor calculation
  2/5 spi: bcm63xx-hsspi: fix division by zero for devices without a max speed
  3/5 spi: bcmbca-hsspi: fix division by zero for devices without a max speed
  4/5 spi: apple: fix division by zero in clock divisor calculation
  5/5 spi: atmel: fix division by zero when transfer speed is zero

All five clamp the divisor to 1 Hz, the same approach as the recent
spi-jcore fix.  The division does not trap on the SoCs these drivers run
on: depending on the architecture it produces a bogus divider, a zero
quotient or an undefined value, so the patches remove undefined
arithmetic rather than a crash.

Shao Mingyin (5):
  spi: sifive: fix division by zero in clock divisor calculation
  spi: bcm63xx-hsspi: fix division by zero for devices without a max speed
  spi: bcmbca-hsspi: fix division by zero for devices without a max speed
  spi: apple: fix division by zero in clock divisor calculation
  spi: atmel: fix division by zero when transfer speed is zero

 drivers/spi/spi-apple.c         | 6 +++++-
 drivers/spi/spi-atmel.c         | 3 ++-
 drivers/spi/spi-bcm63xx-hsspi.c | 3 +++
 drivers/spi/spi-bcmbca-hsspi.c  | 3 +++
 drivers/spi/spi-sifive.c        | 6 +++++-
 5 files changed, 18 insertions(+), 3 deletions(-)

---
base-commit: 7649ba73f9e7e1e04d0b46213e39c79ae09dd55c

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] spi: sifive: fix division by zero in clock divisor calculation
  2026-11-06 15:47 [PATCH 0/5] spi: fix division by zero with a zero transfer speed shao.mingyin
@ 2026-11-06 15:47 ` shao.mingyin
  2026-11-06 15:47 ` [PATCH 2/5] spi: bcm63xx-hsspi: fix division by zero for devices without a max speed shao.mingyin
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: shao.mingyin @ 2026-11-06 15:47 UTC (permalink / raw)
  To: broonie, linux-spi
  Cc: linux-kernel, linux-riscv, pjw, samuel.holland, william.zhang,
	kursad.oney, jonas.gorski, bcm-kernel-feedback-list, anand.gore,
	florian.fainelli, rafal, linux-arm-kernel, sven, j, neal, asahi,
	ryan.wanner, nicolas.ferre, alexandre.belloni, claudiu.beznea

From: Shao Mingyin <shao.mingyin@zte.com.cn>

A SPI device without a valid speed (no spi-max-frequency property, or
created through the spidev sysfs new_device interface without a speed)
gets max_speed_hz == 0.  spi_setup() only clamps that to the controller
limit when host->max_speed_hz is set, and this driver does not set it, so
the zero reaches sifive_spi_prep_transfer() and DIV_ROUND_UP() divides
by it.

On RISC-V the divide instruction returns all ones instead of trapping,
so the controller is programmed with a bogus clock divider rather than
the rate the device asked for.

Clamp the divisor to 1 Hz so the divider calculation is well defined.

Fixes: 484a9a68d669 ("spi: sifive: Add driver for the SiFive SPI controller")
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>

---

diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
index cee4d92e46f4..9c1f674f5921 100644
--- a/drivers/spi/spi-sifive.c
+++ b/drivers/spi/spi-sifive.c
@@ -168,10 +168,14 @@ sifive_spi_prep_transfer(struct sifive_spi *spi, struct spi_device *device,
 			 struct spi_transfer *t)
 {
 	u32 cr;
+	u32 speed_hz;
 	unsigned int mode;
 
+	/* A device with max_speed_hz == 0 must not divide by zero */
+	speed_hz = max_t(u32, t->speed_hz, 1);
+
 	/* Calculate and program the clock rate */
-	cr = DIV_ROUND_UP(clk_get_rate(spi->clk) >> 1, t->speed_hz) - 1;
+	cr = DIV_ROUND_UP(clk_get_rate(spi->clk) >> 1, speed_hz) - 1;
 	cr &= SIFIVE_SPI_SCKDIV_DIV_MASK;
 	sifive_spi_write(spi, SIFIVE_SPI_REG_SCKDIV, cr);

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/5] spi: bcm63xx-hsspi: fix division by zero for devices without a max speed
  2026-11-06 15:47 [PATCH 0/5] spi: fix division by zero with a zero transfer speed shao.mingyin
  2026-11-06 15:47 ` [PATCH 1/5] spi: sifive: fix division by zero in clock divisor calculation shao.mingyin
@ 2026-11-06 15:47 ` shao.mingyin
  2026-11-06 15:48 ` [PATCH 3/5] spi: bcmbca-hsspi: " shao.mingyin
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: shao.mingyin @ 2026-11-06 15:47 UTC (permalink / raw)
  To: broonie, linux-spi
  Cc: linux-kernel, linux-riscv, pjw, samuel.holland, william.zhang,
	kursad.oney, jonas.gorski, bcm-kernel-feedback-list, anand.gore,
	florian.fainelli, rafal, linux-arm-kernel, sven, j, neal, asahi,
	ryan.wanner, nicolas.ferre, alexandre.belloni, claudiu.beznea

From: Shao Mingyin <shao.mingyin@zte.com.cn>

A SPI device whose max_speed_hz is zero (no spi-max-frequency property,
or created through the spidev sysfs new_device interface without a
speed) leaves the transfer speed at zero.  spi_setup() would only clamp
it if host->max_speed_hz was set, which this driver does not do, so
bcm63xx_hsspi_set_clk() divides by zero in DIV_ROUND_UP().

The division does not trap on MIPS or arm64.  The quotient is undefined
or zero, so the clock control register is programmed with a meaningless
value.

Clamp the requested rate to 1 Hz before computing the divider.

Fixes: 142168eba9dc ("spi: bcm63xx-hsspi: add bcm63xx HSSPI driver")
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>

---

diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index abfbf97faf7b..319951fba387 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -469,6 +469,9 @@ static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
 	unsigned int profile = spi_get_chipselect(spi, 0);
 	u32 reg;
 
+	/* A device with max_speed_hz == 0 must not divide by zero */
+	hz = max_t(int, hz, 1);
+
 	reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
 	__raw_writel(CLK_CTRL_ACCUM_RST_ON_LOOP | reg,
 		     bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile));

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/5] spi: bcmbca-hsspi: fix division by zero for devices without a max speed
  2026-11-06 15:47 [PATCH 0/5] spi: fix division by zero with a zero transfer speed shao.mingyin
  2026-11-06 15:47 ` [PATCH 1/5] spi: sifive: fix division by zero in clock divisor calculation shao.mingyin
  2026-11-06 15:47 ` [PATCH 2/5] spi: bcm63xx-hsspi: fix division by zero for devices without a max speed shao.mingyin
@ 2026-11-06 15:48 ` shao.mingyin
  2026-11-06 15:48 ` [PATCH 4/5] spi: apple: fix division by zero in clock divisor calculation shao.mingyin
  2026-11-06 15:48 ` [PATCH 5/5] spi: atmel: fix division by zero when transfer speed is zero shao.mingyin
  4 siblings, 0 replies; 6+ messages in thread
From: shao.mingyin @ 2026-11-06 15:48 UTC (permalink / raw)
  To: broonie, linux-spi
  Cc: linux-kernel, linux-riscv, pjw, samuel.holland, william.zhang,
	kursad.oney, jonas.gorski, bcm-kernel-feedback-list, anand.gore,
	florian.fainelli, rafal, linux-arm-kernel, sven, j, neal, asahi,
	ryan.wanner, nicolas.ferre, alexandre.belloni, claudiu.beznea

From: Shao Mingyin <shao.mingyin@zte.com.cn>

A SPI device whose max_speed_hz is zero (no spi-max-frequency property,
or created through the spidev sysfs new_device interface without a
speed) leaves the transfer speed at zero.  spi_setup() would only clamp
it if host->max_speed_hz was set, which this driver does not do, so
bcmbca_hsspi_set_clk() divides by zero in DIV_ROUND_UP().

On arm64 the division returns zero instead of trapping: the inner
DIV_ROUND_UP() yields zero, which is then used as the divisor of the
outer one, so the clock control register is programmed with a
meaningless value.

Clamp the requested rate to 1 Hz before computing the divider.

Fixes: a38a2233f23b ("spi: bcmbca-hsspi: Add driver for newer HSSPI controller")
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>

---

diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c
index 8c01475886e8..84015110557a 100644
--- a/drivers/spi/spi-bcmbca-hsspi.c
+++ b/drivers/spi/spi-bcmbca-hsspi.c
@@ -196,6 +196,9 @@ static void bcmbca_hsspi_set_clk(struct bcmbca_hsspi *bs,
 	unsigned int profile = spi_get_chipselect(spi, 0);
 	u32 reg;
 
+	/* A device with max_speed_hz == 0 must not divide by zero */
+	hz = max_t(int, hz, 1);
+
 	reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
 	__raw_writel(CLK_CTRL_ACCUM_RST_ON_LOOP | reg,
 		     bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile));

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 4/5] spi: apple: fix division by zero in clock divisor calculation
  2026-11-06 15:47 [PATCH 0/5] spi: fix division by zero with a zero transfer speed shao.mingyin
                   ` (2 preceding siblings ...)
  2026-11-06 15:48 ` [PATCH 3/5] spi: bcmbca-hsspi: " shao.mingyin
@ 2026-11-06 15:48 ` shao.mingyin
  2026-11-06 15:48 ` [PATCH 5/5] spi: atmel: fix division by zero when transfer speed is zero shao.mingyin
  4 siblings, 0 replies; 6+ messages in thread
From: shao.mingyin @ 2026-11-06 15:48 UTC (permalink / raw)
  To: broonie, linux-spi
  Cc: linux-kernel, linux-riscv, pjw, samuel.holland, william.zhang,
	kursad.oney, jonas.gorski, bcm-kernel-feedback-list, anand.gore,
	florian.fainelli, rafal, linux-arm-kernel, sven, j, neal, asahi,
	ryan.wanner, nicolas.ferre, alexandre.belloni, claudiu.beznea

From: Shao Mingyin <shao.mingyin@zte.com.cn>

A SPI device without a valid speed (no spi-max-frequency property, or
created through the spidev sysfs new_device interface without a speed)
gets max_speed_hz == 0.  spi_setup() only clamps that to the controller
limit when host->max_speed_hz is set, and this driver does not set it, so
the zero reaches apple_spi_prep_transfer() and DIV_ROUND_UP() divides by
it.

On arm64 the divide instruction returns zero instead of trapping, so
CLKDIV is programmed as zero.  That selects the fastest clock and can
exceed the rate the attached device supports.

Clamp the divisor to 1 Hz so the divider calculation is well defined.

Fixes: c36212b2610d ("spi: apple: Add driver for Apple SPI controller")
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>

---

diff --git a/drivers/spi/spi-apple.c b/drivers/spi/spi-apple.c
index 61eefb08d2a7..8dbf05936db1 100644
--- a/drivers/spi/spi-apple.c
+++ b/drivers/spi/spi-apple.c
@@ -196,9 +196,13 @@ static void apple_spi_set_cs(struct spi_device *device, bool is_high)
 static bool apple_spi_prep_transfer(struct apple_spi *spi, struct spi_transfer *t)
 {
 	u32 cr, fifo_threshold;
+	u32 speed_hz;
+
+	/* A device with max_speed_hz == 0 must not divide by zero */
+	speed_hz = max_t(u32, t->speed_hz, 1);
 
 	/* Calculate and program the clock rate */
-	cr = DIV_ROUND_UP(clk_get_rate(spi->clk), t->speed_hz);
+	cr = DIV_ROUND_UP(clk_get_rate(spi->clk), speed_hz);
 	reg_write(spi, APPLE_SPI_CLKDIV, min_t(u32, cr, APPLE_SPI_CLKDIV_MAX));
 
 	/* Update bits per word */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 5/5] spi: atmel: fix division by zero when transfer speed is zero
  2026-11-06 15:47 [PATCH 0/5] spi: fix division by zero with a zero transfer speed shao.mingyin
                   ` (3 preceding siblings ...)
  2026-11-06 15:48 ` [PATCH 4/5] spi: apple: fix division by zero in clock divisor calculation shao.mingyin
@ 2026-11-06 15:48 ` shao.mingyin
  4 siblings, 0 replies; 6+ messages in thread
From: shao.mingyin @ 2026-11-06 15:48 UTC (permalink / raw)
  To: broonie, linux-spi
  Cc: linux-kernel, linux-riscv, pjw, samuel.holland, william.zhang,
	kursad.oney, jonas.gorski, bcm-kernel-feedback-list, anand.gore,
	florian.fainelli, rafal, linux-arm-kernel, sven, j, neal, asahi,
	ryan.wanner, nicolas.ferre, alexandre.belloni, claudiu.beznea

From: Shao Mingyin <shao.mingyin@zte.com.cn>

atmel_spi_one_transfer() calls atmel_spi_set_xfer_speed() for every
transfer.  A device whose max_speed_hz is zero (no spi-max-frequency
property, or created through the spidev sysfs new_device interface
without a speed) leaves the transfer speed at zero, and the divider
calculation divides by it.  spi_setup() would only clamp the speed if
host->max_speed_hz was set, which this driver does not do.

On cores without a hardware divider this reports "Division by zero in
kernel" and dumps a stack trace, and on cores with one the quotient is
silently zero; in both cases the existing "too high" check then rejects
the transfer.

Clamp the divisor to 1 Hz so the zero never reaches the division.

Fixes: d3b72c7e6bf3 ("spi: atmel: add support for changing message transfer speed")
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>

---

diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index ffc896e4621a..deebf7afabbc 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -922,8 +922,9 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
 	/*
 	 * Calculate the lowest divider that satisfies the
 	 * constraint, assuming div32/fdiv/mbz == 0.
+	 * A device with max_speed_hz == 0 must not divide by zero.
 	 */
-	scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz);
+	scbr = DIV_ROUND_UP(bus_hz, max_t(u32, xfer->speed_hz, 1));
 
 	/*
 	 * If the resulting divider doesn't fit into the

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-11-06 15:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-06 15:47 [PATCH 0/5] spi: fix division by zero with a zero transfer speed shao.mingyin
2026-11-06 15:47 ` [PATCH 1/5] spi: sifive: fix division by zero in clock divisor calculation shao.mingyin
2026-11-06 15:47 ` [PATCH 2/5] spi: bcm63xx-hsspi: fix division by zero for devices without a max speed shao.mingyin
2026-11-06 15:48 ` [PATCH 3/5] spi: bcmbca-hsspi: " shao.mingyin
2026-11-06 15:48 ` [PATCH 4/5] spi: apple: fix division by zero in clock divisor calculation shao.mingyin
2026-11-06 15:48 ` [PATCH 5/5] spi: atmel: fix division by zero when transfer speed is zero shao.mingyin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®