[PATCH 1/2] clocksource/drivers/arm_arch_timer_mmio: Refactor for early init
Stephan Gerhold
stephan.gerhold at linaro.org
Wed Jun 10 10:53:10 PDT 2026
In preparation of restoring support for using arm,armv7-timer-mem as an
early timer, refactor the driver to allow early initialization without
a device pointer. Replace uses of dev_() logging with pr_(), replace devm
helpers with manual cleanup or scope-based cleanup helpers where possible.
Create a new arch_timer_mmio_init() function that performs the
initialization and registration without a device pointer.
This is not very pretty, although given that the driver cannot be removed
at runtime due to .suppress_bind_attrs = true, at least the overhead for
the manual resource management is limited.
Signed-off-by: Stephan Gerhold <stephan.gerhold at linaro.org>
---
drivers/clocksource/arm_arch_timer_mmio.c | 139 +++++++++++++++++-------------
1 file changed, 79 insertions(+), 60 deletions(-)
diff --git a/drivers/clocksource/arm_arch_timer_mmio.c b/drivers/clocksource/arm_arch_timer_mmio.c
index d10362692fdd..5cb94051c4be 100644
--- a/drivers/clocksource/arm_arch_timer_mmio.c
+++ b/drivers/clocksource/arm_arch_timer_mmio.c
@@ -10,7 +10,9 @@
#define pr_fmt(fmt) "arch_timer_mmio: " fmt
+#include <linux/cleanup.h>
#include <linux/clockchips.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/of_irq.h>
@@ -191,17 +193,16 @@ static irqreturn_t arch_timer_mmio_handler(int irq, void *dev_id)
return IRQ_NONE;
}
-static struct arch_timer_mem_frame *find_best_frame(struct platform_device *pdev)
+static struct arch_timer_mem_frame *find_best_frame(struct arch_timer *at)
{
struct arch_timer_mem_frame *frame, *best_frame = NULL;
- struct arch_timer *at = platform_get_drvdata(pdev);
void __iomem *cntctlbase;
u32 cnttidr;
cntctlbase = ioremap(at->gt_block->cntctlbase, at->gt_block->size);
if (!cntctlbase) {
- dev_err(&pdev->dev, "Can't map CNTCTLBase @ %pa\n",
- &at->gt_block->cntctlbase);
+ pr_err("Can't map CNTCTLBase @ %pa\n",
+ &at->gt_block->cntctlbase);
return NULL;
}
@@ -277,22 +278,21 @@ static void arch_timer_mmio_setup(struct arch_timer *at, int irq)
clocksource_register_hz(&at->cs, at->rate);
}
-static int arch_timer_mmio_frame_register(struct platform_device *pdev,
- struct arch_timer_mem_frame *frame)
+static int arch_timer_mmio_frame_register(struct arch_timer *at,
+ struct arch_timer_mem_frame *frame,
+ struct device_node *np)
{
- struct arch_timer *at = platform_get_drvdata(pdev);
- struct device_node *np = pdev->dev.of_node;
int ret, irq;
u32 rate;
- if (!devm_request_mem_region(&pdev->dev, frame->cntbase, frame->size,
- "arch_mem_timer"))
+ if (!request_mem_region(frame->cntbase, frame->size, "arch_mem_timer"))
return -EBUSY;
- at->base = devm_ioremap(&pdev->dev, frame->cntbase, frame->size);
+ at->base = ioremap(frame->cntbase, frame->size);
if (!at->base) {
- dev_err(&pdev->dev, "Can't map frame's registers\n");
- return -ENXIO;
+ pr_err("Can't map frame's registers @ %pa\n", &frame->cntbase);
+ ret = -ENXIO;
+ goto err_release_region;
}
/*
@@ -310,49 +310,56 @@ static int arch_timer_mmio_frame_register(struct platform_device *pdev,
at->rate = arch_timer_get_rate();
irq = at->access == VIRT_ACCESS ? frame->virt_irq : frame->phys_irq;
- ret = devm_request_irq(&pdev->dev, irq, arch_timer_mmio_handler,
- IRQF_TIMER | IRQF_NO_AUTOEN, "arch_mem_timer",
- &at->evt);
+ ret = request_irq(irq, arch_timer_mmio_handler,
+ IRQF_TIMER | IRQF_NO_AUTOEN, "arch_mem_timer",
+ &at->evt);
if (ret) {
- dev_err(&pdev->dev, "Failed to request mem timer irq\n");
- return ret;
+ pr_err("Failed to request mem timer irq for frame @ %pa\n",
+ &frame->cntbase);
+ goto err_iounmap;
}
/* Afer this point, we're not allowed to fail anymore */
arch_timer_mmio_setup(at, irq);
return 0;
+
+err_iounmap:
+ iounmap(at->base);
+err_release_region:
+ release_mem_region(frame->cntbase, frame->size);
+ return ret;
}
-static int of_populate_gt_block(struct platform_device *pdev,
- struct arch_timer *at)
+static int of_populate_gt_block(struct device_node *np, struct arch_timer_mem *gt_block)
{
struct resource res;
- if (of_address_to_resource(pdev->dev.of_node, 0, &res))
+ if (of_address_to_resource(np, 0, &res))
return -EINVAL;
- at->gt_block->cntctlbase = res.start;
- at->gt_block->size = resource_size(&res);
+ gt_block->cntctlbase = res.start;
+ gt_block->size = resource_size(&res);
- for_each_available_child_of_node_scoped(pdev->dev.of_node, frame_node) {
+ for_each_available_child_of_node_scoped(np, frame_node) {
struct arch_timer_mem_frame *frame;
u32 n;
if (of_property_read_u32(frame_node, "frame-number", &n)) {
- dev_err(&pdev->dev, FW_BUG "Missing frame-number\n");
+ pr_err(FW_BUG "Missing frame-number for %pOF\n",
+ frame_node);
return -EINVAL;
}
if (n >= ARCH_TIMER_MEM_MAX_FRAMES) {
- dev_err(&pdev->dev,
- FW_BUG "Wrong frame-number, only 0-%u are permitted\n",
- ARCH_TIMER_MEM_MAX_FRAMES - 1);
+ pr_err(FW_BUG "Wrong frame-number %u for %pOF, only 0-%u are permitted\n",
+ n, frame_node, ARCH_TIMER_MEM_MAX_FRAMES - 1);
return -EINVAL;
}
- frame = &at->gt_block->frame[n];
+ frame = >_block->frame[n];
if (frame->valid) {
- dev_err(&pdev->dev, FW_BUG "Duplicated frame-number\n");
+ pr_err(FW_BUG "Duplicated frame-number %u for %pOF\n",
+ n, frame_node);
return -EINVAL;
}
@@ -371,50 +378,62 @@ static int of_populate_gt_block(struct platform_device *pdev,
return 0;
}
-static int arch_timer_mmio_probe(struct platform_device *pdev)
+static struct arch_timer *arch_timer_mmio_init(struct arch_timer_mem *gt_block,
+ struct device_node *np)
{
+ struct arch_timer *at __free(kfree) = kzalloc_obj(*at);
struct arch_timer_mem_frame *frame;
- struct arch_timer *at;
- struct device_node *np;
int ret;
- np = pdev->dev.of_node;
-
- at = devm_kmalloc(&pdev->dev, sizeof(*at), GFP_KERNEL | __GFP_ZERO);
if (!at)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
+
+ at->gt_block = gt_block;
+
+ frame = find_best_frame(at);
+ if (!frame) {
+ pr_err("Unable to find a suitable frame in timer @ %pa\n",
+ &at->gt_block->cntctlbase);
+ return ERR_PTR(-EINVAL);
+ }
+
+ ret = arch_timer_mmio_frame_register(at, frame, np);
+ if (ret)
+ return ERR_PTR(ret);
+
+ pr_info("mmio timer running at %lu.%02luMHz (%s)\n",
+ (unsigned long)at->rate / 1000000,
+ (unsigned long)(at->rate / 10000) % 100,
+ at->access == VIRT_ACCESS ? "virt" : "phys");
+
+ return_ptr(at);
+}
+
+static int arch_timer_mmio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct arch_timer_mem *gt_block;
+ struct arch_timer *at;
+ int ret;
if (np) {
- at->gt_block = devm_kmalloc(&pdev->dev, sizeof(*at->gt_block),
- GFP_KERNEL | __GFP_ZERO);
- if (!at->gt_block)
+ gt_block = devm_kzalloc(&pdev->dev, sizeof(*gt_block),
+ GFP_KERNEL);
+ if (!gt_block)
return -ENOMEM;
- ret = of_populate_gt_block(pdev, at);
+ ret = of_populate_gt_block(np, gt_block);
if (ret)
return ret;
} else {
- at->gt_block = dev_get_platdata(&pdev->dev);
- }
-
- platform_set_drvdata(pdev, at);
-
- frame = find_best_frame(pdev);
- if (!frame) {
- dev_err(&pdev->dev,
- "Unable to find a suitable frame in timer @ %pa\n",
- &at->gt_block->cntctlbase);
- return -EINVAL;
+ gt_block = dev_get_platdata(&pdev->dev);
}
- ret = arch_timer_mmio_frame_register(pdev, frame);
- if (!ret)
- dev_info(&pdev->dev,
- "mmio timer running at %lu.%02luMHz (%s)\n",
- (unsigned long)at->rate / 1000000,
- (unsigned long)(at->rate / 10000) % 100,
- at->access == VIRT_ACCESS ? "virt" : "phys");
+ at = arch_timer_mmio_init(gt_block, np);
+ if (IS_ERR(at))
+ return PTR_ERR(at);
- return ret;
+ platform_set_drvdata(pdev, at);
+ return 0;
}
static const struct of_device_id arch_timer_mmio_of_table[] = {
--
2.54.0
More information about the linux-arm-kernel
mailing list