In leon_init_timers(), we should carefully handle several refcounting bugs: (1) we should use of_get_child_by_name() instead of of_find_node_by_name() as the of_find_xxx API will automatically decrease the refcount of its 'from' argument. (2) we should carefully call of_node_put() for the references returned by OF APIs. Fixes: 53aea7caf2e2 ("SPARC/LEON: find IRQCTRL and Timer via OF-Tree, instead of hardcoded.") Signed-off-by: Liang He <windhl@xxxxxxx> --- arch/sparc/kernel/leon_kernel.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 39229940d725..917b45b2ceaf 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -305,7 +305,7 @@ static irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) void __init leon_init_timers(void) { int irq, eirq; - struct device_node *rootnp, *np, *nnp; + struct device_node *rootnp = NULL, *np = NULL, *nnp = NULL; struct property *pp; int len; int icsel; @@ -337,26 +337,35 @@ void __init leon_init_timers(void) amba_system_id = *(unsigned long *)pp->value; /* Find IRQMP IRQ Controller Registers base adr otherwise bail out */ - np = of_find_node_by_name(rootnp, "GAISLER_IRQMP"); + np = of_get_child_by_name(rootnp, "GAISLER_IRQMP"); if (!np) { - np = of_find_node_by_name(rootnp, "01_00d"); - if (!np) + np = of_get_child_by_name(rootnp, "01_00d"); + if (!np) { + of_node_put(rootnp); goto bad; + } } pp = of_find_property(np, "reg", &len); - if (!pp) + of_node_put(np); + if (!pp) { + of_node_put(rootnp); goto bad; + } leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value; /* Find GPTIMER Timer Registers base address otherwise bail out. */ nnp = rootnp; + + retry: - np = of_find_node_by_name(nnp, "GAISLER_GPTIMER"); + np = of_get_child_by_name(nnp, "GAISLER_GPTIMER"); if (!np) { - np = of_find_node_by_name(nnp, "01_011"); - if (!np) + np = of_get_child_by_name(nnp, "01_011"); + if (!np) { + of_node_put(nnp); goto bad; + } } ampopts = 0; @@ -366,6 +375,7 @@ void __init leon_init_timers(void) if (ampopts == 0) { /* Skip this instance, resource already * allocated by other OS */ + of_node_put(nnp); nnp = np; goto retry; } @@ -382,6 +392,9 @@ void __init leon_init_timers(void) if (pp) leon3_gptimer_irq = *(unsigned int *)pp->value; + of_node_put(nnp); + of_node_put(np); + if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq)) goto bad; -- 2.25.1