All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4] timers: Add support for RZ/N1 SoCs timers
@ 2026-07-17  9:55 Herve Codina (Schneider Electric)
  2026-07-17  9:55 ` [PATCH v3 1/4] dt-bindings: timer: Add the Renesas RZ/N1 timer Herve Codina (Schneider Electric)
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Herve Codina (Schneider Electric) @ 2026-07-17  9:55 UTC (permalink / raw)
  To: Wolfram Sang, Herve Codina, Daniel Lezcano, Thomas Gleixner,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm
  Cc: linux-renesas-soc, linux-kernel, devicetree, Pascal Eberhard,
	Miquel Raynal, Thomas Petazzoni

The Renesas RZ/N1 SoCs family has two timers block controller
available.

Each controller is charge of 8 timers (six 16-bit timers + two 32-bit
timers).

Each timer has its own interrupt, its own prescaler that can be used to
device the clock by 25 (timers block are fed with a 25 MHz clock) and
all timers can work in either one-shot or periodic mode.

This series adds support for those timers blocks.

Best regards,
Hervé

Changes v2 -> v3
  v2: https://lore.kernel.org/all/20260429115054.158160-1-herve.codina@bootlin.com/

  Rebase on top of v7.2-rc1.

  Patch 1, 3 and 4:
    - Add 'Reviewed-by: Geert Uytterhoeven'

  Patch 2:
    - Fix typos in commit log.
    - Split Kconfig 'depends on' in 2 lines.
    - Fix indentation, space and alignment in code.
    - Fix dev_err_probe() conversion format.
    - Introduce rzn1_timer_setup_timers() and rzn1_timer_register_clkevt()
      to avoid code duplication in rzn1_timer_probe_{first,other}()
    - Add '.suppress_bind_attrs = true'.

Changes v1 -> v2
  v1: https://lore.kernel.org/all/20260331152616.197031-1-herve.codina@bootlin.com/

  Rebase on top of v7.1-rc1.

  Patch 1:
    - Drop minItems related to interrupts property
    - Add 'Reviewed-by: Krzysztof Kozlowski'

  Patches 2, 3 and 4:
    No changes

Herve Codina (Schneider Electric) (4):
  dt-bindings: timer: Add the Renesas RZ/N1 timer
  clocksource/drivers: Add support for the Renesas RZ/N1 timers
  ARM: dts: r9a06g032: Add support for timers
  MAINTAINERS: Add the Renesas RZ/N1 timers driver entry

 .../bindings/timer/renesas,rzn1-timer.yaml    |  74 +++
 MAINTAINERS                                   |   7 +
 arch/arm/boot/dts/renesas/r9a06g032.dtsi      |  34 ++
 drivers/clocksource/Kconfig                   |  11 +
 drivers/clocksource/Makefile                  |   1 +
 drivers/clocksource/timer-rzn1.c              | 455 ++++++++++++++++++
 6 files changed, 582 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/renesas,rzn1-timer.yaml
 create mode 100644 drivers/clocksource/timer-rzn1.c

-- 
2.55.0


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

* [PATCH v3 1/4] dt-bindings: timer: Add the Renesas RZ/N1 timer
  2026-07-17  9:55 [PATCH v3 0/4] timers: Add support for RZ/N1 SoCs timers Herve Codina (Schneider Electric)
@ 2026-07-17  9:55 ` Herve Codina (Schneider Electric)
  2026-07-17  9:55 ` [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers Herve Codina (Schneider Electric)
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Herve Codina (Schneider Electric) @ 2026-07-17  9:55 UTC (permalink / raw)
  To: Wolfram Sang, Herve Codina, Daniel Lezcano, Thomas Gleixner,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm
  Cc: linux-renesas-soc, linux-kernel, devicetree, Pascal Eberhard,
	Miquel Raynal, Thomas Petazzoni, Krzysztof Kozlowski

The Renesas RZ/N1 timer block controller is the controller in charge of
timers available in the Renesas RZ/N1 SoCs family.

This controller handles 8 timers:
 - 6 16-bit timers
 - 2 32-bit timers

Signed-off-by: Herve Codina (Schneider Electric) <herve.codina@bootlin.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 .../bindings/timer/renesas,rzn1-timer.yaml    | 74 +++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/renesas,rzn1-timer.yaml

diff --git a/Documentation/devicetree/bindings/timer/renesas,rzn1-timer.yaml b/Documentation/devicetree/bindings/timer/renesas,rzn1-timer.yaml
new file mode 100644
index 000000000000..f00ad941f8cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/renesas,rzn1-timer.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/renesas,rzn1-timer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/N1 timers
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The Renesas RZ/N1 SoCs timers block controller is composed of 8 independent
+  timers.
+    - 6 are 16-bit timers
+    - 2 are 32-bit timers
+
+  Each timer has its own interrupt line and can work in either one-shot or
+  periodic mode.
+
+properties:
+  compatible:
+    items:
+      - const: renesas,r9a06g032-timer   # RZ/N1D
+      - const: renesas,rzn1-timer
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: APB internal bus clock
+
+  clock-names:
+    items:
+      - const: pclk
+
+  power-domains:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 8
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/r9a06g032-sysctrl.h>
+
+    timer@51001000 {
+        compatible = "renesas,r9a06g032-timer", "renesas,rzn1-timer";
+        reg = <0x51001000 0x400>;
+        clocks = <&sysctrl R9A06G032_HCLK_TIMER0>;
+        clock-names = "pclk";
+        power-domains = <&sysctrl>;
+        interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+    };
+...
-- 
2.55.0


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

* [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers
  2026-07-17  9:55 [PATCH v3 0/4] timers: Add support for RZ/N1 SoCs timers Herve Codina (Schneider Electric)
  2026-07-17  9:55 ` [PATCH v3 1/4] dt-bindings: timer: Add the Renesas RZ/N1 timer Herve Codina (Schneider Electric)
@ 2026-07-17  9:55 ` Herve Codina (Schneider Electric)
  2026-07-17 10:08   ` sashiko-bot
  2026-07-17  9:55 ` [PATCH v3 3/4] ARM: dts: r9a06g032: Add support for timers Herve Codina (Schneider Electric)
  2026-07-17  9:55 ` [PATCH v3 4/4] MAINTAINERS: Add the Renesas RZ/N1 timers driver entry Herve Codina (Schneider Electric)
  3 siblings, 1 reply; 7+ messages in thread
From: Herve Codina (Schneider Electric) @ 2026-07-17  9:55 UTC (permalink / raw)
  To: Wolfram Sang, Herve Codina, Daniel Lezcano, Thomas Gleixner,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm
  Cc: linux-renesas-soc, linux-kernel, devicetree, Pascal Eberhard,
	Miquel Raynal, Thomas Petazzoni

The Renesas RZ/N1 timer block controller is the controller in charge of
timers available in the Renesas RZ/N1 SoCs family.

This controller handles 8 timers:
  - 6 16-bit timers
  - 2 32-bit timers

Each timer has its own interrupt, its own prescaler that can be used to
divide the clock by 25 and all of them can work in either one-shot or
periodic mode.

Signed-off-by: Herve Codina (Schneider Electric) <herve.codina@bootlin.com>
---
 drivers/clocksource/Kconfig      |  11 +
 drivers/clocksource/Makefile     |   1 +
 drivers/clocksource/timer-rzn1.c | 455 +++++++++++++++++++++++++++++++
 3 files changed, 467 insertions(+)
 create mode 100644 drivers/clocksource/timer-rzn1.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index d9c76dd443f8..da83483296d5 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -152,6 +152,17 @@ config REALTEK_OTTO_TIMER
 	  RT8391, RTL8392, RTL8393 and RTL8396 and chips of the RTL930x series
 	  such as RTL9301, RTL9302 or RTL9303.
 
+config RZN1_TIMER
+	bool "Renesas RZ/N1 Timer"
+	depends on HAS_IOMEM && COMMON_CLK
+	depends on ARCH_RZN1 || COMPILE_TEST
+	help
+	  Enables support for RZ/N1 SoC timers.
+	  A timers block in RZ/N1 SoCs is composed of 8 timers
+	    - 6 16-bit timers
+	    - 2 32-bit timers
+	  Two timers blocks are available in RZ/N1 SoCs.
+
 config SUN4I_TIMER
 	bool "Sun4i timer driver" if COMPILE_TEST
 	depends on HAS_IOMEM
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index b46376af6b49..464ec6690ab6 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -96,3 +96,4 @@ obj-$(CONFIG_EP93XX_TIMER)		+= timer-ep93xx.o
 obj-$(CONFIG_RALINK_TIMER)		+= timer-ralink.o
 obj-$(CONFIG_NXP_STM_TIMER)		+= timer-nxp-stm.o
 obj-$(CONFIG_RTK_SYSTIMER)		+= timer-realtek.o
+obj-$(CONFIG_RZN1_TIMER)		+= timer-rzn1.o
diff --git a/drivers/clocksource/timer-rzn1.c b/drivers/clocksource/timer-rzn1.c
new file mode 100644
index 000000000000..024f01bb0227
--- /dev/null
+++ b/drivers/clocksource/timer-rzn1.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/N1 timers driver
+ *
+ * Copyright (C) 2026 Schneider-Electric
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sched_clock.h>
+
+/* Per-timer register offsets */
+#define RZN1_TIMER_LOAD_COUNT_REG	0x00
+#define RZN1_TIMER_CURRENT_COUNT_REG	0x04
+#define RZN1_TIMER_CONTROL_REG		0x08
+#define   RZN1_TIMER_CONTROL_INT_UNMASK		BIT(3)
+#define   RZN1_TIMER_CONTROL_ENABLE		BIT(2)
+#define   RZN1_TIMER_CONTROL_AUTORELOAD		BIT(1)
+#define   RZN1_TIMER_CONTROL_PRESCALER_DIV25	BIT(0)
+#define RZN1_TIMER_CLEAR_INT_REG	0x0c
+#define RZN1_TIMER_STATUS_INT0_REG	0x10
+#define RZN1_TIMER_STATUS_INT1_REG	0x14
+
+/*
+ * 8 timers are available. Among those 8 timers, the first 6 timers are 16-bit
+ * timers and the last two ones are 32-bit timers.
+ */
+#define RZN1_TIMER_BASE_INDEX_16BIT_TIMERS	0
+#define RZN1_TIMER_NB_16BIT_TIMERS		6
+#define RZN1_TIMER_LAST_INDEX_16BIT_TIMERS	(RZN1_TIMER_BASE_INDEX_16BIT_TIMERS + \
+						 RZN1_TIMER_NB_16BIT_TIMERS - 1)
+
+#define RZN1_TIMER_BASE_INDEX_32BIT_TIMERS	6
+#define RZN1_TIMER_NB_32BIT_TIMERS		2
+#define RZN1_TIMER_LAST_INDEX_32BIT_TIMERS	(RZN1_TIMER_BASE_INDEX_32BIT_TIMERS + \
+						 RZN1_TIMER_NB_32BIT_TIMERS - 1)
+
+#define RZN1_TIMER_IS_16BIT_TIMER(_i) ((_i) < RZN1_TIMER_BASE_INDEX_32BIT_TIMERS)
+
+/* Total numbers of timers */
+#define RZN1_TIMER_NB_TIMERS	(RZN1_TIMER_NB_16BIT_TIMERS + \
+				 RZN1_TIMER_NB_32BIT_TIMERS)
+
+/* Offset of registers related to the timer number _i in the timers regs area */
+#define RZN1_TIMER_REGS_OFFSET(_i) (0x20 * (_i))
+
+struct rzn1_timer {
+	void __iomem *base;
+	unsigned int width;
+	unsigned long rate;
+	unsigned long hz_period;
+	struct clock_event_device ced;
+};
+
+static int rzn1_timer_config(struct rzn1_timer *timer, u32 period, bool is_periodic)
+{
+	u32 ctrl;
+
+	ctrl = readl(timer->base + RZN1_TIMER_CONTROL_REG);
+
+	/* Disable the timer */
+	writel(ctrl & ~RZN1_TIMER_CONTROL_ENABLE,
+	       timer->base + RZN1_TIMER_CONTROL_REG);
+
+	/* Set the new period */
+	writel(period, timer->base + RZN1_TIMER_LOAD_COUNT_REG);
+
+	/* Prepare the timer mode */
+	if (is_periodic)
+		ctrl |= RZN1_TIMER_CONTROL_AUTORELOAD;
+	else
+		ctrl &= ~RZN1_TIMER_CONTROL_AUTORELOAD;
+
+	/*
+	 * Enable the timer.
+	 *
+	 * This automatically resets the CURRENT_COUNT register.
+	 */
+	ctrl |= RZN1_TIMER_CONTROL_ENABLE;
+	writel(ctrl, timer->base + RZN1_TIMER_CONTROL_REG);
+
+	return 0;
+}
+
+static void rzn1_timer_disable(struct rzn1_timer *timer)
+{
+	u32 ctrl;
+
+	ctrl = readl(timer->base + RZN1_TIMER_CONTROL_REG);
+	ctrl &= ~RZN1_TIMER_CONTROL_ENABLE;
+	writel(ctrl, timer->base + RZN1_TIMER_CONTROL_REG);
+}
+
+static void rzn1_timer_int_enable(struct rzn1_timer *timer)
+{
+	u32 ctrl;
+
+	ctrl = readl(timer->base + RZN1_TIMER_CONTROL_REG);
+	ctrl |= RZN1_TIMER_CONTROL_INT_UNMASK;
+	writel(ctrl, timer->base + RZN1_TIMER_CONTROL_REG);
+}
+
+static irqreturn_t rzn1_timer_interrupt(int irq, void *dev_id)
+{
+	struct rzn1_timer *timer = dev_id;
+
+	/* Ack the interrupt */
+	readl(timer->base + RZN1_TIMER_CLEAR_INT_REG);
+
+	timer->ced.event_handler(&timer->ced);
+	return IRQ_HANDLED;
+}
+
+static int rzn1_clkevt_set_next_event(unsigned long cycles,
+				      struct clock_event_device *evt)
+{
+	struct rzn1_timer *timer = container_of(evt, struct rzn1_timer, ced);
+
+	return rzn1_timer_config(timer, cycles, false);
+}
+
+static int rzn1_clkevt_shutdown(struct clock_event_device *evt)
+{
+	struct rzn1_timer *timer = container_of(evt, struct rzn1_timer, ced);
+
+	rzn1_timer_disable(timer);
+	return 0;
+}
+
+static int rzn1_clkevt_set_periodic(struct clock_event_device *evt)
+{
+	struct rzn1_timer *timer = container_of(evt, struct rzn1_timer, ced);
+
+	rzn1_timer_config(timer, timer->hz_period, true);
+	return 0;
+}
+
+/*
+ * This global lock is used to prevent race conditions during global timers
+ * test and set operation in case the driver is using the async probe option.
+ */
+static DEFINE_MUTEX(rzn1_global_timers_lock);
+
+static int rzn1_timer_instance;
+
+/* scheduler and clocksource */
+static struct rzn1_timer *rzn1_sched_clock;
+
+static u64 notrace rzn1_sched_read(void)
+{
+	return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);
+}
+
+static u64 rzn1_clksrc_read(struct clocksource *cs)
+{
+	return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);
+}
+
+static struct clocksource rzn1_clocksource = {
+	.name = "rzn1_timer_clocksource",
+	.rating = 200,
+	.flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
+	.read = rzn1_clksrc_read,
+};
+
+/* Timers table where 32-bit timers will be assigned per-cpu */
+static struct rzn1_timer *rzn1_tab_timers;
+
+static int rzn1_local_timer_starting_cpu(unsigned int cpu)
+{
+	struct rzn1_timer *timer;
+
+	if (cpu > RZN1_TIMER_NB_32BIT_TIMERS)
+		return -EINVAL;
+
+	timer = &rzn1_tab_timers[cpu + RZN1_TIMER_BASE_INDEX_32BIT_TIMERS];
+
+	timer->ced.cpumask = cpumask_of(cpu);
+	irq_force_affinity(timer->ced.irq, cpumask_of(cpu));
+	clockevents_config_and_register(&timer->ced, timer->rate, 1,
+					GENMASK(timer->width - 1, 0));
+
+	return 0;
+}
+
+static void rzn1_timer_init(struct rzn1_timer *timer, unsigned int index,
+			    void __iomem *timers_base, unsigned long clock_rate)
+{
+	timer->base = timers_base + RZN1_TIMER_REGS_OFFSET(index);
+
+	/* Disable the timer */
+	writel(0, timer->base + RZN1_TIMER_CONTROL_REG);
+
+	/* Clear potential interrupts */
+	readl(timer->base + RZN1_TIMER_CLEAR_INT_REG);
+
+	if (RZN1_TIMER_IS_16BIT_TIMER(index)) {
+		timer->width = 16;
+		/*
+		 * Enable pre-scaler for 16-bit timers.
+		 *
+		 * Timers are fed by a 25MHz clock. With this pre-scaler (1/25)
+		 * enabled, the 16-bit timers resolution is 1 microsecond.
+		 */
+		writel(RZN1_TIMER_CONTROL_PRESCALER_DIV25,
+		       timer->base + RZN1_TIMER_CONTROL_REG);
+		timer->rate = clock_rate / 25;
+	} else {
+		timer->width = 32;
+		timer->rate = clock_rate;
+	}
+	timer->hz_period = DIV_ROUND_UP(timer->rate, HZ);
+}
+
+static void rzn1_timer_clkevt_init_ced(struct rzn1_timer *timer, const char *name,
+				       int irq)
+{
+	timer->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	timer->ced.set_next_event = rzn1_clkevt_set_next_event;
+	timer->ced.set_state_shutdown = rzn1_clkevt_shutdown;
+	timer->ced.set_state_periodic = rzn1_clkevt_set_periodic;
+	timer->ced.cpumask = cpu_possible_mask;
+
+	/*
+	 * 32-bit timers are fed with a 25 MHz clock directly derived from the
+	 * main PLL (1 GHz). The arch timer, ARMv7 CP15 in RZ/N1 SoCs, is fed
+	 * with to a 6.25 MHz clock.
+	 *
+	 * The clock of the RZ/N1 timers block is a stable one and the RZ/N1
+	 * timers have a higher resolution than the ARM CP15 one.
+	 *
+	 * Also those 32-bit RZ/N1 timers are assigned per-cpu.
+	 *
+	 * Use a high rating for the 32-bit RZ/N1 timers in order to have them
+	 * chosen by the system.
+	 */
+	timer->ced.rating = timer->width == 16 ? 200 : 460;
+	timer->ced.owner = THIS_MODULE;
+	timer->ced.name = name;
+	timer->ced.irq = irq;
+}
+
+static int rzn1_timer_setup_timers(struct platform_device *pdev,
+				   struct rzn1_timer *tab_timers,
+				   unsigned int first_timer_index,
+				   unsigned int last_timer_index,
+				   void __iomem *base, unsigned long clock_rate)
+{
+	struct device *dev = &pdev->dev;
+	struct rzn1_timer *timer;
+	unsigned int i;
+	char *name;
+	int irq;
+	int ret;
+
+	for (i = first_timer_index; i <= last_timer_index; i++) {
+		timer = &tab_timers[i];
+
+		rzn1_timer_init(timer, i, base, clock_rate);
+
+		irq = platform_get_irq(pdev, i);
+		if (irq < 0)
+			return irq;
+
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s-%u", dev_name(dev), i);
+		if (!name)
+			return -ENOMEM;
+
+		rzn1_timer_clkevt_init_ced(timer, name, irq);
+
+		ret = devm_request_irq(dev, timer->ced.irq, rzn1_timer_interrupt,
+				       IRQF_TIMER, timer->ced.name, timer);
+		if (ret < 0)
+			return dev_err_probe(dev, irq, "timer%u: Failed to request IRQ\n", i);
+
+		rzn1_timer_int_enable(timer);
+	}
+	return 0;
+}
+
+static void rzn1_timer_register_clkevt(struct rzn1_timer *tab_timers,
+				       unsigned int first_timer_index,
+				       unsigned int last_timer_index)
+{
+	struct rzn1_timer *timer;
+	unsigned int i;
+
+	for (i = first_timer_index; i <= last_timer_index; i++) {
+		timer = &tab_timers[i];
+		clockevents_config_and_register(&timer->ced, timer->rate,
+						1, GENMASK(timer->width - 1, 0));
+	}
+}
+
+static int rzn1_timer_probe_first(struct platform_device *pdev,
+				  struct rzn1_timer *tab_timers,
+				  void __iomem *base, unsigned long clock_rate)
+{
+	struct device *dev = &pdev->dev;
+	struct rzn1_timer *timer;
+	int ret;
+
+	/*
+	 * Probe the first instance. In that case, timers are assigned as
+	 * follow:
+	 *   - First 16-bit timer: clocksource and sched_clock
+	 *   - Other 16-bit timers: clock events for all possible CPUs
+	 *   - 32-bit timers: clock events per CPU
+	 *
+	 * First step, perform all operation that could fail without calling
+	 * clockevents_config_and_register(), sched_clock_register() nor
+	 * cpuhp_setup_state(). Those operation don't have unregister nor
+	 * teardown counterparts and so, once called, we cannot remove the
+	 * related resource.
+	 */
+
+	/*
+	 * First step for 16-bit timers except the first one and all 32-bit
+	 * timers.
+	 */
+	ret = rzn1_timer_setup_timers(pdev, tab_timers,
+				      RZN1_TIMER_BASE_INDEX_16BIT_TIMERS + 1,
+				      RZN1_TIMER_LAST_INDEX_32BIT_TIMERS,
+				      base, clock_rate);
+	if (ret)
+		return ret;
+
+	/*
+	 * Second step, almost all operations that can fail have been called.
+	 * Timers are ready to work. Start with the last operation that can fail,
+	 * installing and invoking hotplug callbacks
+	 */
+	rzn1_tab_timers = tab_timers;
+	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+				"clockevents/rzn1/global_timer:starting",
+				rzn1_local_timer_starting_cpu, NULL);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Setup CPU hotplug state failed\n");
+
+	/*
+	 * At this point, no more operations can fail. Perform remaining
+	 * operations. Starting by handling the first 16-bit timer
+	 */
+	timer = &tab_timers[RZN1_TIMER_BASE_INDEX_16BIT_TIMERS];
+
+	rzn1_timer_init(timer, RZN1_TIMER_BASE_INDEX_16BIT_TIMERS, base, clock_rate);
+	rzn1_timer_config(timer, GENMASK(timer->width - 1, 0), true);
+
+	rzn1_sched_clock = timer;
+
+	sched_clock_register(rzn1_sched_read, rzn1_sched_clock->width, rzn1_sched_clock->rate);
+
+	rzn1_clocksource.mask = CLOCKSOURCE_MASK(rzn1_sched_clock->width);
+	clocksource_register_hz(&rzn1_clocksource, rzn1_sched_clock->rate);
+
+	/*
+	 * Register clockevents only for 16-bit timers. 32-bit timers clockevents
+	 * are registered by CPU hotplug startup function set previously by the
+	 * cpuhp_setup_state() call.
+	 */
+	rzn1_timer_register_clkevt(tab_timers,
+				   RZN1_TIMER_BASE_INDEX_16BIT_TIMERS + 1,
+				   RZN1_TIMER_LAST_INDEX_16BIT_TIMERS);
+
+	return 0;
+}
+
+static int rzn1_timer_probe_other(struct platform_device *pdev,
+				  struct rzn1_timer *tab_timers,
+				  void __iomem *base, unsigned long clock_rate)
+{
+	int ret;
+
+	/*
+	 * Probe other instance(s), i.e. not the first one. In that case,
+	 * all timers are used as clock events and available for all possible
+	 * CPUs
+	 *
+	 * First step, perform all operation that could fail without calling
+	 * clockevents_config_and_register(). Unregister counterpart does not
+	 * exist and so, once called, we cannot remove the related resource.
+	 */
+	ret = rzn1_timer_setup_timers(pdev, tab_timers,
+				      RZN1_TIMER_BASE_INDEX_16BIT_TIMERS,
+				      RZN1_TIMER_LAST_INDEX_32BIT_TIMERS,
+				      base, clock_rate);
+	if (ret)
+		return ret;
+
+	/*
+	 * Second step, all operation that can fail have been called. We can
+	 * register our timers.
+	 */
+	rzn1_timer_register_clkevt(tab_timers,
+				   RZN1_TIMER_BASE_INDEX_16BIT_TIMERS,
+				   RZN1_TIMER_LAST_INDEX_32BIT_TIMERS);
+	return 0;
+}
+
+static int rzn1_timer_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rzn1_timer *tab_timers;
+	unsigned long clock_rate;
+	void __iomem *base;
+	struct clk *clk;
+	int ret;
+
+	tab_timers = devm_kcalloc(dev, RZN1_TIMER_NB_TIMERS, sizeof(*tab_timers),
+				  GFP_KERNEL);
+	if (!tab_timers)
+		return -ENOMEM;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	clk = devm_clk_get_enabled(dev, "pclk");
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk), "Failed to get pclk\n");
+
+	clock_rate = clk_get_rate(clk);
+
+	scoped_guard(mutex, &rzn1_global_timers_lock) {
+		ret = !rzn1_timer_instance ?
+			rzn1_timer_probe_first(pdev, tab_timers, base, clock_rate) :
+			rzn1_timer_probe_other(pdev, tab_timers, base, clock_rate);
+		if (!ret)
+			rzn1_timer_instance++;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id rzn1_timer_of_match[] = {
+	{ .compatible = "renesas,rzn1-timer", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver rzn1_timer_driver = {
+	.driver = {
+		.name = "rzn1_timer",
+		.of_match_table = rzn1_timer_of_match,
+		.suppress_bind_attrs = true,
+	},
+};
+builtin_platform_driver_probe(rzn1_timer_driver, rzn1_timer_probe);
-- 
2.55.0


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

* [PATCH v3 3/4] ARM: dts: r9a06g032: Add support for timers
  2026-07-17  9:55 [PATCH v3 0/4] timers: Add support for RZ/N1 SoCs timers Herve Codina (Schneider Electric)
  2026-07-17  9:55 ` [PATCH v3 1/4] dt-bindings: timer: Add the Renesas RZ/N1 timer Herve Codina (Schneider Electric)
  2026-07-17  9:55 ` [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers Herve Codina (Schneider Electric)
@ 2026-07-17  9:55 ` Herve Codina (Schneider Electric)
  2026-07-17  9:55 ` [PATCH v3 4/4] MAINTAINERS: Add the Renesas RZ/N1 timers driver entry Herve Codina (Schneider Electric)
  3 siblings, 0 replies; 7+ messages in thread
From: Herve Codina (Schneider Electric) @ 2026-07-17  9:55 UTC (permalink / raw)
  To: Wolfram Sang, Herve Codina, Daniel Lezcano, Thomas Gleixner,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm
  Cc: linux-renesas-soc, linux-kernel, devicetree, Pascal Eberhard,
	Miquel Raynal, Thomas Petazzoni

In the Renesas RZ/N1 SoCs family, two timers block are available.

Each block contains 8 timers composed of 6 16-bits timers and 2 32-bits
timers.

Each timer has its own interrupt line.

Describe those timers blocks.

Signed-off-by: Herve Codina (Schneider Electric) <herve.codina@bootlin.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 arch/arm/boot/dts/renesas/r9a06g032.dtsi | 34 ++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/arch/arm/boot/dts/renesas/r9a06g032.dtsi b/arch/arm/boot/dts/renesas/r9a06g032.dtsi
index 442ea26b40f5..ba3f011e8c17 100644
--- a/arch/arm/boot/dts/renesas/r9a06g032.dtsi
+++ b/arch/arm/boot/dts/renesas/r9a06g032.dtsi
@@ -722,6 +722,40 @@ gpioirqmux: interrupt-controller@51000480 {
 			status = "disabled";
 		};
 
+		timer0: timer@51001000 {
+			compatible = "renesas,r9a06g032-timer", "renesas,rzn1-timer";
+			reg = <0x51001000 0x400>;
+			clocks = <&sysctrl R9A06G032_HCLK_TIMER0>;
+			clock-names = "pclk";
+			power-domains = <&sysctrl>;
+			interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		timer1: timer@51002000 {
+			compatible = "renesas,r9a06g032-timer", "renesas,rzn1-timer";
+			reg = <0x51002000 0x400>;
+			clocks = <&sysctrl R9A06G032_HCLK_TIMER1>;
+			clock-names = "pclk";
+			power-domains = <&sysctrl>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
 		can0: can@52104000 {
 			compatible = "renesas,r9a06g032-sja1000", "renesas,rzn1-sja1000";
 			reg = <0x52104000 0x800>;
-- 
2.55.0


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

* [PATCH v3 4/4] MAINTAINERS: Add the Renesas RZ/N1 timers driver entry
  2026-07-17  9:55 [PATCH v3 0/4] timers: Add support for RZ/N1 SoCs timers Herve Codina (Schneider Electric)
                   ` (2 preceding siblings ...)
  2026-07-17  9:55 ` [PATCH v3 3/4] ARM: dts: r9a06g032: Add support for timers Herve Codina (Schneider Electric)
@ 2026-07-17  9:55 ` Herve Codina (Schneider Electric)
  3 siblings, 0 replies; 7+ messages in thread
From: Herve Codina (Schneider Electric) @ 2026-07-17  9:55 UTC (permalink / raw)
  To: Wolfram Sang, Herve Codina, Daniel Lezcano, Thomas Gleixner,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Geert Uytterhoeven, Magnus Damm
  Cc: linux-renesas-soc, linux-kernel, devicetree, Pascal Eberhard,
	Miquel Raynal, Thomas Petazzoni

After contributing the driver, add myself as the maintainer for the
Renesas RZ/N1 timers driver.

Signed-off-by: Herve Codina (Schneider Electric) <herve.codina@bootlin.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 15011f5752a9..17fd5f749344 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23025,6 +23025,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
 F:	drivers/rtc/rtc-rzn1.c
 
+RENESAS RZ/N1 TIMERS DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	linux-renesas-soc@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/timer/renesas,rzn1-timer.yaml
+F:	drivers/clocksource/timer-rzn1.c
+
 RENESAS RZ/N1 USBF CONTROLLER DRIVER
 M:	Herve Codina <herve.codina@bootlin.com>
 L:	linux-renesas-soc@vger.kernel.org
-- 
2.55.0


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

* Re: [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers
  2026-07-17  9:55 ` [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers Herve Codina (Schneider Electric)
@ 2026-07-17 10:08   ` sashiko-bot
  2026-07-20 15:42     ` Herve Codina
  0 siblings, 1 reply; 7+ messages in thread
From: sashiko-bot @ 2026-07-17 10:08 UTC (permalink / raw)
  To: Herve Codina (Schneider Electric); +Cc: wsa+renesas, devicetree, conor+dt, robh

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Off-by-one error in CPU bounds check allows out-of-bounds array access in the hotplug callback.
- [High] A 16-bit high-frequency clocksource is incorrectly flagged with CLOCK_SOURCE_SUSPEND_NONSTOP, breaking system suspend timekeeping.
- [High] Probe incorrectly returns a positive IRQ number on devm_request_irq failure.
- [High] Missing teardown callback in cpuhp_setup_state causes a Use-After-Free of clockevent devices.
- [Medium] Down-counting timer values are potentially returned directly, breaking the requirement for monotonic increasing counters.
- [Medium] Failing CPU bringup by returning an error from a CPU hotplug starting callback.
--

--- Patch [2]: [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers ---
commit 67eeb3e62e1eb246f2738740b9b5319a484b8d50
Author: Herve Codina (Schneider Electric) <herve.codina@bootlin.com>

clocksource/drivers: Add support for the Renesas RZ/N1 timers

The Renesas RZ/N1 timer block controller is the controller in charge of
timers available in the Renesas RZ/N1 SoCs family. This controller handles
8 timers: 6 16-bit timers and 2 32-bit timers.

> diff --git a/drivers/clocksource/timer-rzn1.c b/drivers/clocksource/timer-rzn1.c
> new file mode 100644
> index 0000000000000..024f01bb0227b
> --- /dev/null
> +++ b/drivers/clocksource/timer-rzn1.c

[ ... ]

> +static u64 notrace rzn1_sched_read(void)
> +{
> +	return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);
> +}
> +
> +static u64 rzn1_clksrc_read(struct clocksource *cs)
> +{
> +	return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);
> +}

[Severity: Medium]
Since RZN1_TIMER_LOAD_COUNT_REG is used earlier to set the timer period,
does this hardware act as a down-counter?

If the hardware counts downward, will returning the raw value here break the
timekeeping requirement for monotonically increasing values?

> +static struct clocksource rzn1_clocksource = {
> +	.name = "rzn1_timer_clocksource",
> +	.rating = 200,
> +	.flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,

[Severity: High]
Is it safe to flag a 16-bit clocksource with CLOCK_SOURCE_SUSPEND_NONSTOP?

Since a 16-bit counter fed by a high-frequency clock will wrap around very
quickly, will this cause massive wall time jumps if the system suspends for
longer than the wrap interval?

> +	.read = rzn1_clksrc_read,
> +};
> +
> +/* Timers table where 32-bit timers will be assigned per-cpu */
> +static struct rzn1_timer *rzn1_tab_timers;
> +
> +static int rzn1_local_timer_starting_cpu(unsigned int cpu)
> +{
> +	struct rzn1_timer *timer;
> +
> +	if (cpu > RZN1_TIMER_NB_32BIT_TIMERS)
> +		return -EINVAL;

[Severity: Medium]
Will returning an error like -EINVAL completely abort the hotplug process
for any CPU beyond the first two?

Should this return 0 instead, allowing additional CPUs to still boot online
and rely on a global broadcast timer?

[Severity: High]
Also, does the greater-than condition here have an off-by-one error?

If RZN1_TIMER_NB_32BIT_TIMERS is 2, a cpu value of 2 bypasses this check.

> +
> +	timer = &rzn1_tab_timers[cpu + RZN1_TIMER_BASE_INDEX_32BIT_TIMERS];

[Severity: High]
If a cpu value of 2 bypassed the check above, will this access out of bounds?

The array is only sized for 8 elements total. Adding a cpu value of 2 to
RZN1_TIMER_BASE_INDEX_32BIT_TIMERS (which is 6) computes an index of 8.

[ ... ]

> +static int rzn1_timer_setup_timers(struct platform_device *pdev,
> +				   struct rzn1_timer *tab_timers,
> +				   unsigned int first_timer_index,
> +				   unsigned int last_timer_index,
> +				   void __iomem *base, unsigned long clock_rate)
> +{

[ ... ]

> +		ret = devm_request_irq(dev, timer->ced.irq, rzn1_timer_interrupt,
> +				       IRQF_TIMER, timer->ced.name, timer);
> +		if (ret < 0)
> +			return dev_err_probe(dev, irq, "timer%u: Failed to request IRQ\n", i);

[Severity: High]
Will calling dev_err_probe() with irq return the positive IRQ number back to
the caller instead of the negative ret code?

If the driver probe returns a positive integer, won't the driver core assume
the probe succeeded despite the failure?

[ ... ]

> +static int rzn1_timer_probe_first(struct platform_device *pdev,
> +				  struct rzn1_timer *tab_timers,
> +				  void __iomem *base, unsigned long clock_rate)
> +{

[ ... ]

> +	/*
> +	 * Second step, almost all operations that can fail have been called.
> +	 * Timers are ready to work. Start with the last operation that can fail,
> +	 * installing and invoking hotplug callbacks
> +	 */
> +	rzn1_tab_timers = tab_timers;
> +	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> +				"clockevents/rzn1/global_timer:starting",
> +				rzn1_local_timer_starting_cpu, NULL);

[Severity: High]
Does passing a NULL teardown callback here leave registered clockevent
devices dangling if a subsequent step fails during probe?

If the driver fails and frees its timer structures via devres, or if a CPU
is dynamically offlined later, will this lack of teardown cause a
use-after-free in the clockevents core?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260717095552.767475-1-herve.codina@bootlin.com?part=2

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

* Re: [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers
  2026-07-17 10:08   ` sashiko-bot
@ 2026-07-20 15:42     ` Herve Codina
  0 siblings, 0 replies; 7+ messages in thread
From: Herve Codina @ 2026-07-20 15:42 UTC (permalink / raw)
  To: sashiko-bot; +Cc: sashiko-reviews, wsa+renesas, devicetree, conor+dt, robh

Hi,

On Fri, 17 Jul 2026 10:08:26 +0000
sashiko-bot@kernel.org wrote:

> Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
> - [High] Off-by-one error in CPU bounds check allows out-of-bounds array access in the hotplug callback.
> - [High] A 16-bit high-frequency clocksource is incorrectly flagged with CLOCK_SOURCE_SUSPEND_NONSTOP, breaking system suspend timekeeping.
> - [High] Probe incorrectly returns a positive IRQ number on devm_request_irq failure.
> - [High] Missing teardown callback in cpuhp_setup_state causes a Use-After-Free of clockevent devices.
> - [Medium] Down-counting timer values are potentially returned directly, breaking the requirement for monotonic increasing counters.
> - [Medium] Failing CPU bringup by returning an error from a CPU hotplug starting callback.
> --
> 
> --- Patch [2]: [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers ---
> commit 67eeb3e62e1eb246f2738740b9b5319a484b8d50
> Author: Herve Codina (Schneider Electric) <herve.codina@bootlin.com>
> 
> clocksource/drivers: Add support for the Renesas RZ/N1 timers
> 
> The Renesas RZ/N1 timer block controller is the controller in charge of
> timers available in the Renesas RZ/N1 SoCs family. This controller handles
> 8 timers: 6 16-bit timers and 2 32-bit timers.
> 
> > diff --git a/drivers/clocksource/timer-rzn1.c b/drivers/clocksource/timer-rzn1.c
> > new file mode 100644
> > index 0000000000000..024f01bb0227b
> > --- /dev/null
> > +++ b/drivers/clocksource/timer-rzn1.c  
> 
> [ ... ]
> 
> > +static u64 notrace rzn1_sched_read(void)
> > +{
> > +	return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);
> > +}
> > +
> > +static u64 rzn1_clksrc_read(struct clocksource *cs)
> > +{
> > +	return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);
> > +}  
> 
> [Severity: Medium]
> Since RZN1_TIMER_LOAD_COUNT_REG is used earlier to set the timer period,
> does this hardware act as a down-counter?
> 
> If the hardware counts downward, will returning the raw value here break the
> timekeeping requirement for monotonically increasing values?

The timer counter is an incrementing counter.
It is compared to the LOAD_COUNT register value to trig an interrupt. 

> 
> > +static struct clocksource rzn1_clocksource = {
> > +	.name = "rzn1_timer_clocksource",
> > +	.rating = 200,
> > +	.flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,  
> 
> [Severity: High]
> Is it safe to flag a 16-bit clocksource with CLOCK_SOURCE_SUSPEND_NONSTOP?
> 
> Since a 16-bit counter fed by a high-frequency clock will wrap around very
> quickly, will this cause massive wall time jumps if the system suspends for
> longer than the wrap interval?

This flag shouldn't be present. Will be removed in the next iteration.

> 
> > +	.read = rzn1_clksrc_read,
> > +};
> > +
> > +/* Timers table where 32-bit timers will be assigned per-cpu */
> > +static struct rzn1_timer *rzn1_tab_timers;
> > +
> > +static int rzn1_local_timer_starting_cpu(unsigned int cpu)
> > +{
> > +	struct rzn1_timer *timer;
> > +
> > +	if (cpu > RZN1_TIMER_NB_32BIT_TIMERS)
> > +		return -EINVAL;  
> 
> [Severity: Medium]
> Will returning an error like -EINVAL completely abort the hotplug process
> for any CPU beyond the first two?
> 
> Should this return 0 instead, allowing additional CPUs to still boot online
> and rely on a global broadcast timer?

Indeed, returning 0 is better even if we should reach this case on RZ/N1 SoCs.
Will update in the next iteration.

> 
> [Severity: High]
> Also, does the greater-than condition here have an off-by-one error?
> 
> If RZN1_TIMER_NB_32BIT_TIMERS is 2, a cpu value of 2 bypasses this check.

Will update in the next iteration.

> 
> > +
> > +	timer = &rzn1_tab_timers[cpu + RZN1_TIMER_BASE_INDEX_32BIT_TIMERS];  
> 
> [Severity: High]
> If a cpu value of 2 bypassed the check above, will this access out of bounds?
> 
> The array is only sized for 8 elements total. Adding a cpu value of 2 to
> RZN1_TIMER_BASE_INDEX_32BIT_TIMERS (which is 6) computes an index of 8.

The cpu value check against RZN1_TIMER_NB_32BIT_TIMERS will be update in the
next iteration. This possible out of bound access will not exist anymore.

> 
> [ ... ]
> 
> > +static int rzn1_timer_setup_timers(struct platform_device *pdev,
> > +				   struct rzn1_timer *tab_timers,
> > +				   unsigned int first_timer_index,
> > +				   unsigned int last_timer_index,
> > +				   void __iomem *base, unsigned long clock_rate)
> > +{  
> 
> [ ... ]
> 
> > +		ret = devm_request_irq(dev, timer->ced.irq, rzn1_timer_interrupt,
> > +				       IRQF_TIMER, timer->ced.name, timer);
> > +		if (ret < 0)
> > +			return dev_err_probe(dev, irq, "timer%u: Failed to request IRQ\n", i);  
> 
> [Severity: High]
> Will calling dev_err_probe() with irq return the positive IRQ number back to
> the caller instead of the negative ret code?
> 
> If the driver probe returns a positive integer, won't the driver core assume
> the probe succeeded despite the failure?

Indeed, will be update in the next iteration.

> 
> [ ... ]
> 
> > +static int rzn1_timer_probe_first(struct platform_device *pdev,
> > +				  struct rzn1_timer *tab_timers,
> > +				  void __iomem *base, unsigned long clock_rate)
> > +{  
> 
> [ ... ]
> 
> > +	/*
> > +	 * Second step, almost all operations that can fail have been called.
> > +	 * Timers are ready to work. Start with the last operation that can fail,
> > +	 * installing and invoking hotplug callbacks
> > +	 */
> > +	rzn1_tab_timers = tab_timers;
> > +	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> > +				"clockevents/rzn1/global_timer:starting",
> > +				rzn1_local_timer_starting_cpu, NULL);  
> 
> [Severity: High]
> Does passing a NULL teardown callback here leave registered clockevent
> devices dangling if a subsequent step fails during probe?
> 
> If the driver fails and frees its timer structures via devres, or if a CPU
> is dynamically offlined later, will this lack of teardown cause a
> use-after-free in the clockevents core?

The probe cannot fail after the call to cpuhp_setup_state(). This has been taken
into account. The only case to handle is offlining a CPU (which I am not sure
it could happen in embedded system using a RZ/N1 SoC).

Anyway, will add the teardown function and:
  - Adapt the probe to set IRQ_NOAUTOEN flag on interrupt related to timers
    handled by hotplug.
  - Enable irq hotplug startup function.
  - Disable irq in teardown function.

Best regards,
Hervé

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

end of thread, other threads:[~2026-07-20 15:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-17  9:55 [PATCH v3 0/4] timers: Add support for RZ/N1 SoCs timers Herve Codina (Schneider Electric)
2026-07-17  9:55 ` [PATCH v3 1/4] dt-bindings: timer: Add the Renesas RZ/N1 timer Herve Codina (Schneider Electric)
2026-07-17  9:55 ` [PATCH v3 2/4] clocksource/drivers: Add support for the Renesas RZ/N1 timers Herve Codina (Schneider Electric)
2026-07-17 10:08   ` sashiko-bot
2026-07-20 15:42     ` Herve Codina
2026-07-17  9:55 ` [PATCH v3 3/4] ARM: dts: r9a06g032: Add support for timers Herve Codina (Schneider Electric)
2026-07-17  9:55 ` [PATCH v3 4/4] MAINTAINERS: Add the Renesas RZ/N1 timers driver entry Herve Codina (Schneider Electric)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.