From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 281DA38643B; Sat, 16 May 2026 21:57:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778968653; cv=none; b=tQ2ze82jo6d2RyptaSh+yj5p0QqYgWNlPFUVUsIEds1ct4DdcQFToHlyqzTrC/5bc4veJ+etZNAjSUwQ3FTZTGGS5fyL9e0OCvRFqUCF7y/P1YQV8cx4MQxGdrBfwLXP2lODfuQzfy3UZUGzSsAn/KGxF/P7gONrDco95sYkyjA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778968653; c=relaxed/simple; bh=7wxpOJISV76f+OA+eUJDFOYKOmSTMyJ0sT0aUgy6Jx0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=S/r24PFUo7bGrww/VpLuzwT5pbjf/SY4i3YQYxWynPaNToDRlExgcTqwya6pBgRprxZSYuNickagTWTadPddsqy9MSvetgtxJLn7tGqdN/i0YtzItL+yao6QZdSn5yN9Gls3QMvWe3BgdmsO0hKLeVt/eCCySqTIfkKNt0bbvtg= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=pass smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=DUbRHobk; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="DUbRHobk" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 072CD3FA133; Sat, 16 May 2026 23:57:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1778968650; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=Q0h8RiPN75sqVf0my0iCAciaGj/g/mvtHx8ng9fbWfM=; b=DUbRHobkuF7yBfQa5mNCHXmv5Ux84Ai+pPKjohj2QEn7RIkFfiXPefsAGPXAXI4p4uonhX wqyQuEfKiHpyjIbu3ueCkrDCsw8PqdtrOPdiN7uhwhyj4nvZHFSEElAFVgWSpdWs43bjXz MEO0RgrKr8VjJbVfExEa5tHLjWRz4J+d0UgQb6Ypo1G0g4DoQb7jwf2KaDro/iROclmlTB ycloH846FKY5vQQIRiWpyp4aQ4rvyACBCywwQRq1sc8SdiSKH0VPIPrg5QGZvewfYYaMkA yCLXTZOPI1qL6PvyTwcQY8qicM0TrkxhM07fuZ3axioeBj+9Ma2KQq+3HcDJJg== From: Caleb James DeLisle To: linux-mips@vger.kernel.org Cc: conor+dt@kernel.org, daniel.lezcano@kernel.org, devicetree@vger.kernel.org, krzk+dt@kernel.org, linux-kernel@vger.kernel.org, naseefkm@gmail.com, robh@kernel.org, tglx@kernel.org, Caleb James DeLisle Subject: [PATCH v4 2/4] clocksource/timer-econet-en751221: Init teardown on error if possible Date: Sat, 16 May 2026 21:57:18 +0000 Message-Id: <20260516215720.4160831-3-cjd@cjdns.fr> In-Reply-To: <20260516215720.4160831-1-cjd@cjdns.fr> References: <20260516215720.4160831-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 As a clocksource, much of the initialization process is irreversible and the impact of a failure to initialize is a failure to boot. That said, good practice is to attempt a clean exit if probing fails, and supporting this pattern will reduce the likelihood that future contributions introduce a bug by trying to teardown after it is no longer possible to do so. Convert the init process into two clearly delineated phases, one which is reverted in case of error, and the other which can't be. Move all IRQ and address resource mapping before that point, and add teardown logic in case of error before the point of no return. Signed-off-by: Caleb James DeLisle --- drivers/clocksource/timer-econet-en751221.c | 82 ++++++++++++--------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/drivers/clocksource/timer-econet-en751221.c b/drivers/clocksource/timer-econet-en751221.c index 4008076b1a21..155471f68e6f 100644 --- a/drivers/clocksource/timer-econet-en751221.c +++ b/drivers/clocksource/timer-econet-en751221.c @@ -24,6 +24,7 @@ static struct { void __iomem *membase[ECONET_NUM_BLOCKS]; + int irq; u32 freq_hz; } econet_timer __ro_after_init; @@ -126,22 +127,9 @@ static void __init cevt_dev_init(uint cpu) iowrite32(U32_MAX, reg_compare(cpu)); } -static int __init cevt_init(struct device_node *np) +static void __init cevt_init(struct device_node *np) { - int i, irq, ret; - - irq = irq_of_parse_and_map(np, 0); - if (irq <= 0) { - pr_err("%pOFn: irq_of_parse_and_map failed", np); - return -EINVAL; - } - - ret = request_percpu_irq(irq, cevt_interrupt, np->name, &econet_timer_pcpu); - - if (ret < 0) { - pr_err("%pOFn: IRQ %d setup failed (%d)\n", np, irq, ret); - goto err_unmap_irq; - } + int i; for_each_possible_cpu(i) { struct clock_event_device *cd = &per_cpu(econet_timer_pcpu, i); @@ -151,21 +139,12 @@ static int __init cevt_init(struct device_node *np) CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_PERCPU; cd->set_next_event = cevt_set_next_event; - cd->irq = irq; + cd->irq = econet_timer.irq; cd->cpumask = cpumask_of(i); cd->name = np->name; cevt_dev_init(i); } - - cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, - "clockevents/econet/timer:starting", - cevt_init_cpu, NULL); - return 0; - -err_unmap_irq: - irq_dispose_mapping(irq); - return ret; } static int __init timer_init(struct device_node *np) @@ -186,22 +165,45 @@ static int __init timer_init(struct device_node *np) econet_timer.membase[i] = of_iomap(np, i); if (!econet_timer.membase[i]) { pr_err("%pOFn: failed to map register [%d]\n", np, i); - return -ENXIO; + ret = -ENXIO; + goto out_membase; } } + econet_timer.irq = irq_of_parse_and_map(np, 0); + if (econet_timer.irq <= 0) { + pr_err("%pOFn: irq_of_parse_and_map failed\n", np); + ret = -EINVAL; + goto out_membase; + } + + ret = request_percpu_irq(econet_timer.irq, cevt_interrupt, np->name, + &econet_timer_pcpu); + + if (ret < 0) { + pr_err("%pOFn: IRQ %d setup failed (%d)\n", np, + econet_timer.irq, ret); + goto out_irq_mapping; + } + + cevt_init(np); + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "clockevents/econet/timer:starting", + cevt_init_cpu, NULL); + if (ret < 0) { + pr_err("%pOFn: cpuhp setup failed (%d)\n", np, ret); + goto out_irq_free; + } + + /* Point of no return, do not attempt to tear down after this. */ + /* For clocksource purposes always read clock zero, whatever the CPU */ ret = clocksource_mmio_init(reg_count(0), np->name, econet_timer.freq_hz, 301, ECONET_BITS, clocksource_mmio_readl_up); - if (ret) { - pr_err("%pOFn: clocksource_mmio_init failed: %d", np, ret); - return ret; - } - - ret = cevt_init(np); - if (ret < 0) - return ret; + if (ret) + pr_err("%pOFn: clocksource_mmio_init failed: %d\n", np, ret); sched_clock_register(sched_clock_read, ECONET_BITS, econet_timer.freq_hz); @@ -211,6 +213,18 @@ static int __init timer_init(struct device_node *np) (econet_timer.freq_hz / 1000) % 1000); return 0; + +out_irq_free: + free_percpu_irq(econet_timer.irq, &econet_timer_pcpu); +out_irq_mapping: + irq_dispose_mapping(econet_timer.irq); +out_membase: + for (int i = 0; i < ARRAY_SIZE(econet_timer.membase); i++) { + if (econet_timer.membase[i]) + iounmap(econet_timer.membase[i]); + } + + return ret; } TIMER_OF_DECLARE(econet_timer_hpt, "econet,en751221-timer", timer_init); -- 2.39.5