Linux RTC
 help / color / mirror / Atom feed
* [PATCH v3 0/4] rtc: pcf85063: Update interrupt support
@ 2026-08-28 16:44 A. Sverdlin
  2026-08-28 16:44 ` [PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout A. Sverdlin
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: A. Sverdlin @ 2026-08-28 16:44 UTC (permalink / raw)
  To: linux-rtc; +Cc: Alexander Sverdlin, Alexandre Belloni, linux-kernel

From: Alexander Sverdlin <alexander.sverdlin@siemens.com>

Add hardware-backed UIE (1 Hz update interrupt) support to the pcf85063
driver. The PCF85063A/RV8263 have no dedicated update-interrupt source,
so chrony and similar tools that rely on RTC_UIE_ON fall back to the
kernel's software polling emulation. This series repurposes the chip's
countdown timer (TCF = 1 Hz, T = 1) to generate a periodic interrupt on
the INT pin, serving UIE entirely in hardware.

Patches 2-3 are preparatory: they fix an AIE race in the interrupt
handler and a lost-alarm-flag race in the clkout helpers.

Patch 1 fixes a pre-existing use-after-free in the clkout clock provider
on unbind, found during review by Sashiko.

Changelog:
v3:
- split into 3 preparatory patches and the final new feature patch
- replaced racy regmap_write() with regmap_update_bits() in IRQ handler
- the timer flag (TF) is write-0-to-clear, so every read-modify-write of
  CTRL2 preserves it by writing it back as 1
v2:
- https://lore.kernel.org/all/20260820112437.3715237-1-alexander.sverdlin@siemens.com/

Alexander Sverdlin (4):
  rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout
  rtc: pcf85063: do not clear AIE in the interrupt handler
  rtc: pcf85063: preserve the alarm flag in clkout register updates
  rtc: pcf85063: add 1 Hz update interrupt (UIE) support

 drivers/rtc/rtc-pcf85063.c | 139 +++++++++++++++++++++++++++++++------
 1 file changed, 118 insertions(+), 21 deletions(-)

-- 
2.55.0


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

* [PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout
  2026-08-28 16:44 [PATCH v3 0/4] rtc: pcf85063: Update interrupt support A. Sverdlin
@ 2026-08-28 16:44 ` A. Sverdlin
  2026-08-28 16:51   ` sashiko-bot
  2026-08-28 16:44 ` [PATCH v3 2/4] rtc: pcf85063: do not clear AIE in the interrupt handler A. Sverdlin
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: A. Sverdlin @ 2026-08-28 16:44 UTC (permalink / raw)
  To: linux-rtc; +Cc: Alexander Sverdlin, Alexandre Belloni, linux-kernel

From: Alexander Sverdlin <alexander.sverdlin@siemens.com>

pcf85063_clkout_register_clk() registered the OF clock provider with the
deprecated of_clk_add_provider() and never removed it, so the provider
kept pointing at freed data after unbind, leading to a use-after-free the
next time the device-tree clock was resolved.

Switch to devm_clk_hw_register() and devm_of_clk_add_hw_provider(): both
the clock and its OF provider are managed resources now, and the provider
is torn down before the clock on unbind.

Register the clock on the parent i2c device instead of the rtc device.
devm_of_clk_add_hw_provider() must use the parent, which owns the
of_node, and the clkout_hw it points at lives in the driver data
allocated on the parent. Tying both to the parent releases them together
on unbind, before the driver data is freed, and keeps their teardown
ordering guaranteed by a single devres list. Registering the clock on the
rtc device instead could defer its unregistration past unbind (e.g. while
a /dev/rtcN fd is open), after clkout_hw has already been freed.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
---
Changelog:
v3:
- new patch (pre-exising issue found by Sashiko)

 drivers/rtc/rtc-pcf85063.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 8cb9ffc73f6d9..ac9ab1c376c0b 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -495,12 +495,13 @@ static const struct clk_ops pcf85063_clkout_ops = {
 	.set_rate = pcf85063_clkout_set_rate,
 };
 
-static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
+static int pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
 {
-	struct clk *clk;
+	struct device *dev = pcf85063->rtc->dev.parent;
 	struct clk_init_data init = {};
-	struct device_node *node = pcf85063->rtc->dev.parent->of_node;
+	struct device_node *node = dev->of_node;
 	struct device_node *fixed_clock;
+	int ret;
 
 	fixed_clock = of_get_child_by_name(node, "clock");
 	if (fixed_clock) {
@@ -510,7 +511,7 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
 		 * registered automatically when being referenced.
 		 */
 		of_node_put(fixed_clock);
-		return NULL;
+		return 0;
 	}
 
 	init.name = "pcf85063-clkout";
@@ -524,12 +525,12 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
 	of_property_read_string(node, "clock-output-names", &init.name);
 
 	/* register the clock */
-	clk = devm_clk_register(&pcf85063->rtc->dev, &pcf85063->clkout_hw);
-
-	if (!IS_ERR(clk))
-		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	ret = devm_clk_hw_register(dev, &pcf85063->clkout_hw);
+	if (ret)
+		return ret;
 
-	return clk;
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+					   &pcf85063->clkout_hw);
 }
 #endif
 
-- 
2.55.0


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

* [PATCH v3 2/4] rtc: pcf85063: do not clear AIE in the interrupt handler
  2026-08-28 16:44 [PATCH v3 0/4] rtc: pcf85063: Update interrupt support A. Sverdlin
  2026-08-28 16:44 ` [PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout A. Sverdlin
@ 2026-08-28 16:44 ` A. Sverdlin
  2026-08-28 17:05   ` sashiko-bot
  2026-08-28 16:44 ` [PATCH v3 3/4] rtc: pcf85063: preserve the alarm flag in clkout register updates A. Sverdlin
  2026-08-28 16:44 ` [PATCH v3 4/4] rtc: pcf85063: add 1 Hz update interrupt (UIE) support A. Sverdlin
  3 siblings, 1 reply; 10+ messages in thread
From: A. Sverdlin @ 2026-08-28 16:44 UTC (permalink / raw)
  To: linux-rtc; +Cc: Alexander Sverdlin, Alexandre Belloni, linux-kernel

From: Alexander Sverdlin <alexander.sverdlin@siemens.com>

The interrupt handler cleared the alarm interrupt enable (AIE) bit while
acknowledging the alarm flag (AF). This races with process-context updates
of AIE in pcf85063_rtc_alarm_irq_enable() and pcf85063_rtc_set_alarm():
a handler running concurrently can clobber an AIE change.

The RTC core already disables the alarm interrupt after a one-shot alarm
via the .alarm_irq_enable callback, so the handler does not need to touch
AIE at all. Acknowledge AF only and leave AIE management to the core.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
---
Changelog:
v3:
- new patch (pre-existing issue found by Sashiko)

 drivers/rtc/rtc-pcf85063.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index ac9ab1c376c0b..af900fe8ae15e 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -238,8 +238,7 @@ static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id)
 	if (val & PCF85063_CTRL2_AF) {
 		rtc_update_irq(pcf85063->rtc, 1, RTC_IRQF | RTC_AF);
 		regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
-				   PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
-				   0);
+				   PCF85063_CTRL2_AF, 0);
 		return IRQ_HANDLED;
 	}
 
-- 
2.55.0


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

* [PATCH v3 3/4] rtc: pcf85063: preserve the alarm flag in clkout register updates
  2026-08-28 16:44 [PATCH v3 0/4] rtc: pcf85063: Update interrupt support A. Sverdlin
  2026-08-28 16:44 ` [PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout A. Sverdlin
  2026-08-28 16:44 ` [PATCH v3 2/4] rtc: pcf85063: do not clear AIE in the interrupt handler A. Sverdlin
@ 2026-08-28 16:44 ` A. Sverdlin
  2026-08-28 16:58   ` sashiko-bot
  2026-08-28 16:44 ` [PATCH v3 4/4] rtc: pcf85063: add 1 Hz update interrupt (UIE) support A. Sverdlin
  3 siblings, 1 reply; 10+ messages in thread
From: A. Sverdlin @ 2026-08-28 16:44 UTC (permalink / raw)
  To: linux-rtc; +Cc: Alexander Sverdlin, Alexandre Belloni, linux-kernel

From: Alexander Sverdlin <alexander.sverdlin@siemens.com>

The clkout rate and enable/disable helpers update CTRL2 with
regmap_update_bits() but leave the alarm flag (AF) out of the mask. AF is
write-0-to-clear, so an AF that gets asserted between the read and the
write of the read-modify-write is written back as 0 and the pending alarm
interrupt is lost.

Add AF to the mask and write it back as 1 (write-1-to-preserve) so a
concurrently asserted alarm flag survives a clkout reconfiguration.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
---
Changelog:
v3:
- new patch

 drivers/rtc/rtc-pcf85063.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index af900fe8ae15e..a3af86456ccfc 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -431,7 +431,8 @@ static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
 		if (clkout_rates[i] == rate)
 			return regmap_update_bits(pcf85063->regmap,
 				PCF85063_REG_CTRL2,
-				PCF85063_REG_CLKO_F_MASK, i);
+				PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
+				i | PCF85063_CTRL2_AF);
 
 	return -EINVAL;
 }
@@ -460,7 +461,8 @@ static int pcf85063_clkout_control(struct clk_hw *hw, bool enable)
 	}
 
 	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
-					PCF85063_REG_CLKO_F_MASK, buf);
+				  PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
+				  buf | PCF85063_CTRL2_AF);
 }
 
 static int pcf85063_clkout_prepare(struct clk_hw *hw)
-- 
2.55.0


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

* [PATCH v3 4/4] rtc: pcf85063: add 1 Hz update interrupt (UIE) support
  2026-08-28 16:44 [PATCH v3 0/4] rtc: pcf85063: Update interrupt support A. Sverdlin
                   ` (2 preceding siblings ...)
  2026-08-28 16:44 ` [PATCH v3 3/4] rtc: pcf85063: preserve the alarm flag in clkout register updates A. Sverdlin
@ 2026-08-28 16:44 ` A. Sverdlin
  2026-08-28 17:00   ` sashiko-bot
  3 siblings, 1 reply; 10+ messages in thread
From: A. Sverdlin @ 2026-08-28 16:44 UTC (permalink / raw)
  To: linux-rtc
  Cc: Alexander Sverdlin, Alexandre Belloni, linux-kernel,
	Adrian Freihofer

From: Alexander Sverdlin <alexander.sverdlin@siemens.com>

The PCF85063A/RV8263 have no dedicated 1 Hz update interrupt, but their
countdown timer can be sourced from a 1 Hz clock (TCF = 1 Hz, T = 1) to
generate a periodic interrupt on the INT pin. Use it to offload UIE to
the hardware, following the pattern of other RTC drivers: the timer is
enabled from set_alarm()/alarm_irq_enable() whenever uie_rtctimer is
active, and the IRQ handler reports RTC_UF when the timer flag (TF) is
set.

RTC_FEATURE_UPDATE_INTERRUPT is now only cleared when no usable interrupt
is wired, preserving the polling emulation for those configurations.

Co-developed-by: Adrian Freihofer <adrian.freihofer@siemens.com>
Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com>
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
---
Changelog:
v3:
- replaced racy regmap_write() with regmap_update_bits() in IRQ handler
- the timer flag (TF) is write-0-to-clear, so every read-modify-write of
  CTRL2 preserves it by writing it back as 1
v2:
- preserve AF bit in pcf85063_set_timer_1hz()
- faster and less racy (regarding AF flag) pcf85063_rtc_handle_irq()
- https://lore.kernel.org/all/20260820112437.3715237-1-alexander.sverdlin@siemens.com/

 drivers/rtc/rtc-pcf85063.c | 121 +++++++++++++++++++++++++++++++++----
 1 file changed, 108 insertions(+), 13 deletions(-)

diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index a3af86456ccfc..32952e73f2f1c 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -44,6 +44,7 @@
 #define PCF85063_REG_CTRL2		0x01
 #define PCF85063_CTRL2_AF		BIT(6)
 #define PCF85063_CTRL2_AIE		BIT(7)
+#define PCF85063_CTRL2_TF		BIT(3)
 
 #define PCF85063_REG_OFFSET		0x02
 #define PCF85063_OFFSET_SIGN_BIT	6	/* 2's complement sign bit */
@@ -63,6 +64,14 @@
 #define PCF85063_REG_ALM_S		0x0b
 #define PCF85063_AEN			BIT(7)
 
+#define PCF85063_REG_TIMER_VALUE	0x10
+#define PCF85063_REG_TIMER_MODE		0x11
+#define PCF85063_TIMER_MODE_TI_TP	BIT(0)
+#define PCF85063_TIMER_MODE_TIE		BIT(1)
+#define PCF85063_TIMER_MODE_TE		BIT(2)
+#define PCF85063_TIMER_MODE_TCF_MASK	GENMASK(4, 3)
+#define PCF85063_TIMER_MODE_TCF_1HZ	(2 << 3)
+
 struct pcf85063_config {
 	struct regmap_config regmap;
 	unsigned has_alarms:1;
@@ -188,20 +197,75 @@ static int pcf85063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 	return 0;
 }
 
+/*
+ * The chip has no dedicated 1 Hz update interrupt. Drive the countdown timer
+ * at 1 Hz to emulate it, so the RTC core can offload UIE to the hardware
+ * instead of polling. A free-running timer is left untouched to preserve its
+ * phase across the per-second re-arming done by the core.
+ */
+static int pcf85063_set_timer_1hz(struct pcf85063 *pcf85063, bool enable)
+{
+	unsigned int mask = PCF85063_TIMER_MODE_TCF_MASK |
+			    PCF85063_TIMER_MODE_TIE |
+			    PCF85063_TIMER_MODE_TI_TP |
+			    PCF85063_TIMER_MODE_TE;
+	unsigned int mode = 0;
+	unsigned int cur;
+	int ret;
+
+	if (enable)
+		mode = PCF85063_TIMER_MODE_TCF_1HZ | PCF85063_TIMER_MODE_TIE |
+		       PCF85063_TIMER_MODE_TI_TP | PCF85063_TIMER_MODE_TE;
+
+	ret = regmap_read(pcf85063->regmap, PCF85063_REG_TIMER_MODE, &cur);
+	if (ret)
+		return ret;
+
+	if ((cur & mask) == mode)
+		return 0;
+
+	/* Stop the counter before changing its reload value. */
+	ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_TIMER_MODE,
+				 PCF85063_TIMER_MODE_TE, 0);
+	if (ret)
+		return ret;
+
+	if (enable) {
+		ret = regmap_write(pcf85063->regmap, PCF85063_REG_TIMER_VALUE, 1);
+		if (ret)
+			return ret;
+
+		/* Clear TF but preserve AF */
+		ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
+					 PCF85063_CTRL2_TF | PCF85063_CTRL2_AF, PCF85063_CTRL2_AF);
+		if (ret)
+			return ret;
+	}
+
+	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_TIMER_MODE,
+				  mask, mode);
+}
+
 static int pcf85063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
 	struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
 	u8 buf[5];
 	int ret;
 
+	ret = pcf85063_set_timer_1hz(pcf85063, pcf85063->rtc->uie_rtctimer.enabled);
+	if (ret)
+		return ret;
+
 	buf[0] = bin2bcd(alrm->time.tm_sec);
 	buf[1] = bin2bcd(alrm->time.tm_min);
 	buf[2] = bin2bcd(alrm->time.tm_hour);
 	buf[3] = bin2bcd(alrm->time.tm_mday);
 	buf[4] = PCF85063_AEN; /* Do not match on week day */
 
+	/* Preserve TF */
 	ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
-				 PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF, 0);
+				 PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
+				 PCF85063_CTRL2_TF);
 	if (ret)
 		return ret;
 
@@ -211,23 +275,33 @@ static int pcf85063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 		return ret;
 
 	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
-				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
-				  alrm->enabled ? PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF : PCF85063_CTRL2_AF);
+				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
+				  pcf85063->rtc->aie_timer.enabled ?
+				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF :
+				  PCF85063_CTRL2_AF | PCF85063_CTRL2_TF);
 }
 
 static int pcf85063_rtc_alarm_irq_enable(struct device *dev,
 					 unsigned int enabled)
 {
 	struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pcf85063_set_timer_1hz(pcf85063, pcf85063->rtc->uie_rtctimer.enabled);
+	if (ret)
+		return ret;
 
 	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
-				  PCF85063_CTRL2_AIE,
-				  enabled ? PCF85063_CTRL2_AIE : 0);
+				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_TF,
+				  pcf85063->rtc->aie_timer.enabled ?
+				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_TF : PCF85063_CTRL2_TF);
 }
 
 static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id)
 {
 	struct pcf85063 *pcf85063 = dev_id;
+	unsigned long events = RTC_IRQF;
+	irqreturn_t ret = IRQ_NONE;
 	unsigned int val;
 	int err;
 
@@ -236,13 +310,33 @@ static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id)
 		return IRQ_NONE;
 
 	if (val & PCF85063_CTRL2_AF) {
-		rtc_update_irq(pcf85063->rtc, 1, RTC_IRQF | RTC_AF);
+		events |= RTC_AF;
+		val &= ~PCF85063_CTRL2_AF;
+		ret = IRQ_HANDLED;
+	} else {
+		/* Preserve AF if it comes after the above regmap_read() */
+		val |= PCF85063_CTRL2_AF;
+	}
+
+	if (val & PCF85063_CTRL2_TF) {
+		events |= RTC_UF;
+		val &= ~PCF85063_CTRL2_TF;
+		ret = IRQ_HANDLED;
+	} else {
+		/*
+		 * While not documented, TF demonstrates the same
+		 * write-1-to-preserve semantics as AF in real HW
+		 */
+		val |= PCF85063_CTRL2_TF;
+	}
+
+	if (ret == IRQ_HANDLED) {
 		regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
-				   PCF85063_CTRL2_AF, 0);
-		return IRQ_HANDLED;
+				   PCF85063_CTRL2_AF | PCF85063_CTRL2_TF, val);
+		rtc_update_irq(pcf85063->rtc, 1, events);
 	}
 
-	return IRQ_NONE;
+	return ret;
 }
 
 static int pcf85063_read_offset(struct device *dev, long *offset)
@@ -431,8 +525,8 @@ static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
 		if (clkout_rates[i] == rate)
 			return regmap_update_bits(pcf85063->regmap,
 				PCF85063_REG_CTRL2,
-				PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
-				i | PCF85063_CTRL2_AF);
+				PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
+				i | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF);
 
 	return -EINVAL;
 }
@@ -461,8 +555,8 @@ static int pcf85063_clkout_control(struct clk_hw *hw, bool enable)
 	}
 
 	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
-				  PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
-				  buf | PCF85063_CTRL2_AF);
+				  PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
+				  buf | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF);
 }
 
 static int pcf85063_clkout_prepare(struct clk_hw *hw)
@@ -609,6 +703,7 @@ static int pcf85063_probe(struct device *dev, struct regmap *regmap, int irq,
 			dev_warn(&pcf85063->rtc->dev,
 				 "unable to request IRQ, alarms disabled\n");
 		} else {
+			set_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features);
 			set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
 			device_init_wakeup(dev, true);
 			err = dev_pm_set_wake_irq(dev, irq);
-- 
2.55.0


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

* Re: [PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout
  2026-08-28 16:44 ` [PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout A. Sverdlin
@ 2026-08-28 16:51   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-28 16:51 UTC (permalink / raw)
  To: A. Sverdlin; +Cc: linux-rtc, Alexandre Belloni

> From: Alexander Sverdlin <alexander.sverdlin@siemens.com>
> 
> pcf85063_clkout_register_clk() registered the OF clock provider with the
> deprecated of_clk_add_provider() and never removed it, so the provider
> kept pointing at freed data after unbind, leading to a use-after-free the
> next time the device-tree clock was resolved.
> 
> Switch to devm_clk_hw_register() and devm_of_clk_add_hw_provider(): both
> the clock and its OF provider are managed resources now, and the provider
> is torn down before the clock on unbind.
> 
> Register the clock on the parent i2c device instead of the rtc device.
> devm_of_clk_add_hw_provider() must use the parent, which owns the
> of_node, and the clkout_hw it points at lives in the driver data
> allocated on the parent. Tying both to the parent releases them together
> on unbind, before the driver data is freed, and keeps their teardown
> ordering guaranteed by a single devres list. Registering the clock on the
> rtc device instead could defer its unregistration past unbind (e.g. while
> a /dev/rtcN fd is open), after clkout_hw has already been freed.
> 
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260828164445.3907839-1-alexander.sverdlin@siemens.com?part=1


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

* Re: [PATCH v3 3/4] rtc: pcf85063: preserve the alarm flag in clkout register updates
  2026-08-28 16:44 ` [PATCH v3 3/4] rtc: pcf85063: preserve the alarm flag in clkout register updates A. Sverdlin
@ 2026-08-28 16:58   ` sashiko-bot
  2026-08-28 17:21     ` Sverdlin, Alexander
  0 siblings, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-08-28 16:58 UTC (permalink / raw)
  To: A. Sverdlin; +Cc: linux-rtc, Alexandre Belloni

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] The patch correctly fixes the read-modify-write race condition for the alarm flag (AF) in the clkout helpers, but it completely misses the exact same bug in `pcf85063_rtc_alarm_irq_enable()`.
--

commit 10941c8a0cce0c4a8065c1c9da8c092b66df0282
Author: Alexander Sverdlin <alexander.sverdlin@siemens.com>

rtc: pcf85063: preserve the alarm flag in clkout register updates

This commit fixes a read-modify-write race condition for the alarm flag (AF)
in the clkout helpers by ensuring AF is preserved during regmap updates.

> diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
> index af900fe8ae15e..a3af86456ccfc 100644
> --- a/drivers/rtc/rtc-pcf85063.c
> +++ b/drivers/rtc/rtc-pcf85063.c
> @@ -431,7 +431,8 @@ static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
>  		if (clkout_rates[i] == rate)
>  			return regmap_update_bits(pcf85063->regmap,
>  				PCF85063_REG_CTRL2,
> -				PCF85063_REG_CLKO_F_MASK, i);
> +				PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
> +				i | PCF85063_CTRL2_AF);
>  
>  	return -EINVAL;
>  }
> @@ -460,7 +461,8 @@ static int pcf85063_clkout_control(struct clk_hw *hw, bool enable)
>  	}
>  
>  	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
> -					PCF85063_REG_CLKO_F_MASK, buf);
> +				  PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
> +				  buf | PCF85063_CTRL2_AF);
>  }

[Severity: High]
This is a pre-existing issue, but does pcf85063_rtc_alarm_irq_enable() also
suffer from the exact same race condition that this patch addresses?

Looking at drivers/rtc/rtc-pcf85063.c:pcf85063_rtc_alarm_irq_enable():

	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
				  PCF85063_CTRL2_AIE,
				  enabled ? PCF85063_CTRL2_AIE : 0);

If the alarm fires exactly during this read-modify-write operation, wouldn't
the hardware alarm flag (AF) be inadvertently cleared since it is omitted from
the mask? This could lead to a lost RTC alarm interrupt and cause the system
to miss critical wakeups.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260828164445.3907839-1-alexander.sverdlin@siemens.com?part=3

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

* Re: [PATCH v3 4/4] rtc: pcf85063: add 1 Hz update interrupt (UIE) support
  2026-08-28 16:44 ` [PATCH v3 4/4] rtc: pcf85063: add 1 Hz update interrupt (UIE) support A. Sverdlin
@ 2026-08-28 17:00   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-28 17:00 UTC (permalink / raw)
  To: A. Sverdlin; +Cc: linux-rtc, Alexandre Belloni

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] The driver completely ignores the requested alarm enable parameters, breaking generic `alarmtimers` (POSIX timers) and system wakeups.

Pre-existing issues:
- [High] In `pcf85063_rtc_alarm_irq_enable()`, the `PCF85063_CTRL2_AF` (Alarm Flag) bit is omitted from the `regmap_update_bits` mask and value, which can inadvertently clear a pending alarm interrupt.
--

commit 72f77be444d700f19ce672423be21e8db8ec0a3d
Author: Alexander Sverdlin <alexander.sverdlin@siemens.com>

rtc: pcf85063: add 1 Hz update interrupt (UIE) support

The PCF85063A/RV8263 have no dedicated 1 Hz update interrupt, but their
countdown timer can be sourced from a 1 Hz clock (TCF = 1 Hz, T = 1) to
generate a periodic interrupt on the INT pin. Use it to offload UIE to
the hardware, following the pattern of other RTC drivers.

> diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
> index a3af86456ccfc..32952e73f2f1c 100644
> --- a/drivers/rtc/rtc-pcf85063.c
> +++ b/drivers/rtc/rtc-pcf85063.c

[ ... ]

> @@ -211,23 +275,33 @@ static int pcf85063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
>  		return ret;
>  
>  	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
> -				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
> -				  alrm->enabled ? PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF : PCF85063_CTRL2_AF);
> +				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
> +				  pcf85063->rtc->aie_timer.enabled ?
> +				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF :
> +				  PCF85063_CTRL2_AF | PCF85063_CTRL2_TF);
>  }

[Severity: High]
Does this code ignore the requested alrm->enabled parameter in favor of
pcf85063->rtc->aie_timer.enabled?

The RTC core multiplexes various timers onto the hardware alarm and passes the
desired hardware state via alrm->enabled here and via the enabled parameter in
pcf85063_rtc_alarm_irq_enable().

By checking aie_timer.enabled instead, it appears the driver will only enable
the hardware alarm for the legacy ioctl alarm. If a generic alarmtimer (such
as a system wakealarm or a POSIX timer) reaches the front of the queue, won't
aie_timer.enabled be false, silencing the requested alarm?

>  static int pcf85063_rtc_alarm_irq_enable(struct device *dev,
>  					 unsigned int enabled)
>  {
>  	struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = pcf85063_set_timer_1hz(pcf85063, pcf85063->rtc->uie_rtctimer.enabled);
> +	if (ret)
> +		return ret;
>  
>  	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
> -				  PCF85063_CTRL2_AIE,
> -				  enabled ? PCF85063_CTRL2_AIE : 0);
> +				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_TF,
> +				  pcf85063->rtc->aie_timer.enabled ?
> +				  PCF85063_CTRL2_AIE | PCF85063_CTRL2_TF : PCF85063_CTRL2_TF);
>  }

[Severity: High]
This is a pre-existing issue, but does this read-modify-write omit
PCF85063_CTRL2_AF from the mask, potentially clearing a pending alarm?

Since the AF bit in PCF85063_REG_CTRL2 is write-0-to-clear, if the hardware
asserts the AF interrupt between the internal register read and write of this
operation, the read value will have AF=0. Because AF is not masked,
regmap_update_bits() will write back AF=0, which unintentionally clears the
newly asserted alarm flag.

Also, similar to pcf85063_rtc_set_alarm() above, does this code
inappropriately ignore the enabled parameter passed by the core?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260828164445.3907839-1-alexander.sverdlin@siemens.com?part=4

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

* Re: [PATCH v3 2/4] rtc: pcf85063: do not clear AIE in the interrupt handler
  2026-08-28 16:44 ` [PATCH v3 2/4] rtc: pcf85063: do not clear AIE in the interrupt handler A. Sverdlin
@ 2026-08-28 17:05   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-08-28 17:05 UTC (permalink / raw)
  To: A. Sverdlin; +Cc: Alexandre Belloni, linux-rtc

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing cleanup of wake IRQ and wakeup source for the SPI device leads to memory leaks and a use-after-free of the IRQ number upon unbind.
--

commit a20e38cbd0dbed144e6a870cac13aec94ffaa637
Author: Alexander Sverdlin <alexander.sverdlin@siemens.com>

rtc: pcf85063: do not clear AIE in the interrupt handler

The interrupt handler cleared the AIE bit while acknowledging the AF flag, which
could race with process-context updates. The RTC core already manages disabling
the alarm interrupt, so this patch limits the handler to only acknowledging AF.

> diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
> index ac9ab1c376c0b..af900fe8ae15e 100644
> --- a/drivers/rtc/rtc-pcf85063.c
> +++ b/drivers/rtc/rtc-pcf85063.c
> @@ -238,8 +238,7 @@ static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id)
>  	if (val & PCF85063_CTRL2_AF) {
>  		rtc_update_irq(pcf85063->rtc, 1, RTC_IRQF | RTC_AF);
>  		regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
> -				   PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
> -				   0);
> +				   PCF85063_CTRL2_AF, 0);
>  		return IRQ_HANDLED;
>  	}
>  

[Severity: High]
This is a pre-existing issue, but I noticed a potential leak during driver
unbind for the SPI variant in this file.

In pcf85063_probe(), the wake IRQ and wakeup source are allocated without
using devres:

drivers/rtc/rtc-pcf85063.c:pcf85063_probe() {
    ...
		} else {
			set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
			device_init_wakeup(dev, true);
			err = dev_pm_set_wake_irq(dev, irq);
    ...
}

The SPI subsystem, unlike I2C, does not automatically clear the wake IRQ or
wakeup source on driver removal. Since the rv8063_driver SPI driver lacks a
.remove callback, could this leak the wake IRQ and wakeup source when the
driver is unbound?

drivers/rtc/rtc-pcf85063.c:
static struct spi_driver rv8063_driver = {
	.driver         = {
		.name   = "rv8063",
		.of_match_table = rv8063_of_match,
	},
	.probe          = rv8063_probe,
	.id_table	= rv8063_id,
};

When the driver is unbound, devm_request_threaded_irq() frees the IRQ via
devres, but dev->power.wakeirq still holds the freed IRQ number and the
wakeup_source remains registered. 

If the system subsequently suspends, dev_pm_arm_wake_irq() iterates over
registered wakeup sources and calls enable_irq_wake() with the freed IRQ
number. Could this access a stale IRQ descriptor and interfere with hardware
state, potentially leading to an unhandled IRQ storm on resume?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260828164445.3907839-1-alexander.sverdlin@siemens.com?part=2

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

* Re: [PATCH v3 3/4] rtc: pcf85063: preserve the alarm flag in clkout register updates
  2026-08-28 16:58   ` sashiko-bot
@ 2026-08-28 17:21     ` Sverdlin, Alexander
  0 siblings, 0 replies; 10+ messages in thread
From: Sverdlin, Alexander @ 2026-08-28 17:21 UTC (permalink / raw)
  To: sashiko-reviews@lists.linux.dev
  Cc: linux-rtc@vger.kernel.org, alexandre.belloni@bootlin.com

Hi all,

On Fri, 2026-08-28 at 16:58 +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> 
> Pre-existing issues:
> - [High] The patch correctly fixes the read-modify-write race condition for the alarm flag (AF) in the clkout helpers, but it completely misses the exact same bug in `pcf85063_rtc_alarm_irq_enable()`.
> --
> 
> commit 10941c8a0cce0c4a8065c1c9da8c092b66df0282
> Author: Alexander Sverdlin <alexander.sverdlin@siemens.com>
> 
> rtc: pcf85063: preserve the alarm flag in clkout register updates
> 
> This commit fixes a read-modify-write race condition for the alarm flag (AF)
> in the clkout helpers by ensuring AF is preserved during regmap updates.
> 
> > diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
> > index af900fe8ae15e..a3af86456ccfc 100644
> > --- a/drivers/rtc/rtc-pcf85063.c
> > +++ b/drivers/rtc/rtc-pcf85063.c
> > @@ -431,7 +431,8 @@ static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
> >   		if (clkout_rates[i] == rate)
> >   			return regmap_update_bits(pcf85063->regmap,
> >   				PCF85063_REG_CTRL2,
> > -				PCF85063_REG_CLKO_F_MASK, i);
> > +				PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
> > +				i | PCF85063_CTRL2_AF);
> >   
> >   	return -EINVAL;
> >   }
> > @@ -460,7 +461,8 @@ static int pcf85063_clkout_control(struct clk_hw *hw, bool enable)
> >   	}
> >   
> >   	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
> > -					PCF85063_REG_CLKO_F_MASK, buf);
> > +				  PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF,
> > +				  buf | PCF85063_CTRL2_AF);
> >   }
> 
> [Severity: High]
> This is a pre-existing issue, but does pcf85063_rtc_alarm_irq_enable() also
> suffer from the exact same race condition that this patch addresses?
> 
> Looking at drivers/rtc/rtc-pcf85063.c:pcf85063_rtc_alarm_irq_enable():
> 
> 	return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
> 				  PCF85063_CTRL2_AIE,
> 				  enabled ? PCF85063_CTRL2_AIE : 0);
> 
> If the alarm fires exactly during this read-modify-write operation, wouldn't
> the hardware alarm flag (AF) be inadvertently cleared since it is omitted from
> the mask? This could lead to a lost RTC alarm interrupt and cause the system
> to miss critical wakeups.

I believe, that's intended behaviour, to clear the pending interrupt flag on enable.

-- 
Alexander Sverdlin
Siemens AG
www.siemens.com

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

end of thread, other threads:[~2026-08-28 17:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-28 16:44 [PATCH v3 0/4] rtc: pcf85063: Update interrupt support A. Sverdlin
2026-08-28 16:44 ` [PATCH v3 1/4] rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout A. Sverdlin
2026-08-28 16:51   ` sashiko-bot
2026-08-28 16:44 ` [PATCH v3 2/4] rtc: pcf85063: do not clear AIE in the interrupt handler A. Sverdlin
2026-08-28 17:05   ` sashiko-bot
2026-08-28 16:44 ` [PATCH v3 3/4] rtc: pcf85063: preserve the alarm flag in clkout register updates A. Sverdlin
2026-08-28 16:58   ` sashiko-bot
2026-08-28 17:21     ` Sverdlin, Alexander
2026-08-28 16:44 ` [PATCH v3 4/4] rtc: pcf85063: add 1 Hz update interrupt (UIE) support A. Sverdlin
2026-08-28 17:00   ` sashiko-bot

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