mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout
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> Link: https://patch.msgid.link/20260828164445.3907839-2-alexander.sverdlin@siemens.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
parent
f6550426f2
commit
a451b6bb92
|
|
@ -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);
|
||||
ret = devm_clk_hw_register(dev, &pcf85063->clkout_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
|
||||
return clk;
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
|
||||
&pcf85063->clkout_hw);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user