lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251205011027.720512-5-willmcvicker@google.com>
Date: Fri,  5 Dec 2025 01:10:17 +0000
From: Will McVicker <willmcvicker@...gle.com>
To: Catalin Marinas <catalin.marinas@....com>, Will Deacon <will@...nel.org>, 
	Daniel Lezcano <daniel.lezcano@...aro.org>, Thomas Gleixner <tglx@...utronix.de>, 
	Krzysztof Kozlowski <krzk@...nel.org>, Alim Akhtar <alim.akhtar@...sung.com>
Cc: Will McVicker <willmcvicker@...gle.com>, Donghoon Yu <hoony.yu@...sung.com>, 
	Rob Herring <robh@...nel.org>, John Stultz <jstultz@...gle.com>, 
	Youngmin Nam <youngmin.nam@...sung.com>, Peter Griffin <peter.griffin@...aro.org>, 
	Tudor Ambarus <tudor.ambarus@...aro.org>, 
	"André Draszik" <andre.draszik@...aro.org>, Conor Dooley <conor+dt@...nel.org>, 
	Marek Szyprowski <m.szyprowski@...sung.com>, "Russell King (Oracle)" <linux@...linux.org.uk>, 
	linux-samsung-soc@...r.kernel.org, kernel-team@...roid.com, 
	linux-arm-kernel@...ts.infradead.org, linux-kernel@...r.kernel.org
Subject: [PATCH v7 4/6] clocksource/drivers/exynos_mct: Refactor driver init

This patch cleans up the driver a bit by
- refactoring mct_init_dt() to allow better separation of ARM 32-bit
  specific code and ARM64 code. Ultimately this allows the driver to
  access context data outside of mct_init_dt().
- adds driver data to distinguish the interrupt type which allows
  a single driver init function.

This clean up is in preparation for modularizing the MCT driver for only
ARM64 SoCs.

Signed-off-by: Will McVicker <willmcvicker@...gle.com>
---
 drivers/clocksource/exynos_mct.c | 199 +++++++++++++++++++------------
 1 file changed, 125 insertions(+), 74 deletions(-)

diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index fece6bbc190e..922c2b519a39 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -74,13 +74,22 @@ enum {
 	MCT_INT_PPI
 };
 
+/* Needs to be global for sched_clock_register() since we can't pass in data. */
 static void __iomem *reg_base;
-static unsigned long clk_rate;
-static unsigned int mct_int_type;
-static int mct_irqs[MCT_NR_IRQS];
+
+struct mct_data {
+	unsigned int int_type;
+};
+
+struct mct_context {
+	const struct mct_data *drvdata;
+	unsigned long clk_rate;
+	int mct_irqs[MCT_NR_IRQS];
+};
 
 struct mct_clock_event_device {
 	struct clock_event_device evt;
+	struct mct_context *ctx;
 	unsigned long base;
 	/**
 	 *  The length of the name must be adjusted if number of
@@ -89,6 +98,12 @@ struct mct_clock_event_device {
 	char name[11];
 };
 
+static struct mct_clock_event_device *
+to_mct_clock_event_device(struct clock_event_device *evt)
+{
+	return container_of(evt, struct mct_clock_event_device, evt);
+}
+
 static void exynos4_mct_write(unsigned int value, unsigned long offset)
 {
 	unsigned long stat_addr;
@@ -241,7 +256,7 @@ static cycles_t exynos4_read_current_timer(void)
 }
 #endif
 
-static int __init exynos4_clocksource_init(bool frc_shared)
+static int __init exynos4_clocksource_init(struct mct_context *ctx, bool frc_shared)
 {
 	/*
 	 * When the frc is shared, the main processor should have already
@@ -252,18 +267,9 @@ static int __init exynos4_clocksource_init(bool frc_shared)
 	else
 		exynos4_mct_frc_start();
 
-#if defined(CONFIG_ARM)
-	exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
-	exynos4_delay_timer.freq = clk_rate;
-	register_current_timer_delay(&exynos4_delay_timer);
-
-	sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
-#endif
-
-	if (clocksource_register_hz(&mct_frc, clk_rate))
+	if (clocksource_register_hz(&mct_frc, ctx->clk_rate))
 		panic("%s: can't register clocksource\n", mct_frc.name);
 
-
 	return 0;
 }
 
@@ -297,7 +303,7 @@ static void exynos4_mct_comp0_start(bool periodic, unsigned long cycles)
 	exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
 
 	tcon |= MCT_G_TCON_COMP0_ENABLE;
-	exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
+	exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
 }
 
 static int exynos4_comp_set_next_event(unsigned long cycles,
@@ -325,17 +331,19 @@ static int mct_set_state_periodic(struct clock_event_device *evt)
 	return 0;
 }
 
-static struct clock_event_device mct_comp_device = {
-	.name			= "mct-comp",
-	.features		= CLOCK_EVT_FEAT_PERIODIC |
-				  CLOCK_EVT_FEAT_ONESHOT,
-	.rating			= 250,
-	.set_next_event		= exynos4_comp_set_next_event,
-	.set_state_periodic	= mct_set_state_periodic,
-	.set_state_shutdown	= mct_set_state_shutdown,
-	.set_state_oneshot	= mct_set_state_shutdown,
-	.set_state_oneshot_stopped = mct_set_state_shutdown,
-	.tick_resume		= mct_set_state_shutdown,
+static struct mct_clock_event_device mct_comp_device = {
+	.evt = {
+		.name			= "mct-comp",
+		.features		= CLOCK_EVT_FEAT_PERIODIC |
+					  CLOCK_EVT_FEAT_ONESHOT,
+		.rating			= 250,
+		.set_next_event		= exynos4_comp_set_next_event,
+		.set_state_periodic	= mct_set_state_periodic,
+		.set_state_shutdown	= mct_set_state_shutdown,
+		.set_state_oneshot	= mct_set_state_shutdown,
+		.set_state_oneshot_stopped = mct_set_state_shutdown,
+		.tick_resume		= mct_set_state_shutdown,
+	},
 };
 
 static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
@@ -349,14 +357,16 @@ static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int exynos4_clockevent_init(void)
+static int exynos4_clockevent_init(struct mct_context *ctx)
 {
-	mct_comp_device.cpumask = cpumask_of(0);
-	clockevents_config_and_register(&mct_comp_device, clk_rate,
+	struct clock_event_device *evt = &mct_comp_device.evt;
+
+	mct_comp_device.ctx = ctx;
+	evt->cpumask = cpumask_of(0);
+	clockevents_config_and_register(evt, ctx->clk_rate,
 					0xf, 0xffffffff);
-	if (request_irq(mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr,
-			IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq",
-			&mct_comp_device))
+	if (request_irq(ctx->mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr,
+			IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq", evt))
 		pr_err("%s: request_irq() failed\n", "mct_comp_irq");
 
 	return 0;
@@ -409,18 +419,16 @@ static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
 static int exynos4_tick_set_next_event(unsigned long cycles,
 				       struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt;
+	struct mct_clock_event_device *mevt = to_mct_clock_event_device(evt);
 
-	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	exynos4_mct_tick_start(cycles, mevt);
 	return 0;
 }
 
 static int set_state_shutdown(struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt;
+	struct mct_clock_event_device *mevt = to_mct_clock_event_device(evt);
 
-	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	exynos4_mct_tick_stop(mevt);
 	exynos4_mct_tick_clear(mevt);
 	return 0;
@@ -428,10 +436,9 @@ static int set_state_shutdown(struct clock_event_device *evt)
 
 static int set_state_periodic(struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt;
+	struct mct_clock_event_device *mevt = to_mct_clock_event_device(evt);
 	unsigned long cycles_per_jiffy;
 
-	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult)
 			    >> evt->shift);
 	exynos4_mct_tick_stop(mevt);
@@ -464,6 +471,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 	struct mct_clock_event_device *mevt =
 		per_cpu_ptr(&percpu_mct_tick, cpu);
 	struct clock_event_device *evt = &mevt->evt;
+	struct mct_context *ctx = mevt->ctx;
 
 	evt->name = mevt->name;
 	evt->cpumask = cpumask_of(cpu);
@@ -479,7 +487,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 
 	exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
 
-	if (mct_int_type == MCT_INT_SPI) {
+	if (ctx->drvdata->int_type == MCT_INT_SPI) {
 
 		if (evt->irq == -1)
 			return -EIO;
@@ -487,9 +495,9 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
 		irq_force_affinity(evt->irq, cpumask_of(cpu));
 		enable_irq(evt->irq);
 	} else {
-		enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
+		enable_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ], 0);
 	}
-	clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
+	clockevents_config_and_register(evt, ctx->clk_rate / (TICK_BASE_CNT + 1),
 					0xf, 0x7fffffff);
 
 	return 0;
@@ -500,18 +508,20 @@ static int exynos4_mct_dying_cpu(unsigned int cpu)
 	struct mct_clock_event_device *mevt =
 		per_cpu_ptr(&percpu_mct_tick, cpu);
 	struct clock_event_device *evt = &mevt->evt;
+	struct mct_context *ctx = mevt->ctx;
 
-	if (mct_int_type == MCT_INT_SPI) {
+	if (ctx->drvdata->int_type == MCT_INT_SPI) {
 		if (evt->irq != -1)
 			disable_irq_nosync(evt->irq);
 		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
 	} else {
-		disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
+		disable_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ]);
 	}
 	return 0;
 }
 
-static int __init exynos4_timer_resources(struct device_node *np)
+static int __init exynos4_timer_resources(struct mct_context *ctx,
+					  struct device_node *np)
 {
 	struct clk *mct_clk, *tick_clk;
 
@@ -522,7 +532,7 @@ static int __init exynos4_timer_resources(struct device_node *np)
 	tick_clk = of_clk_get_by_name(np, "fin_pll");
 	if (IS_ERR(tick_clk))
 		panic("%s: unable to determine tick clock rate\n", __func__);
-	clk_rate = clk_get_rate(tick_clk);
+	ctx->clk_rate = clk_get_rate(tick_clk);
 
 	mct_clk = of_clk_get_by_name(np, "mct");
 	if (IS_ERR(mct_clk))
@@ -534,22 +544,20 @@ static int __init exynos4_timer_resources(struct device_node *np)
 
 /**
  * exynos4_timer_interrupts - initialize MCT interrupts
+ * @ctx: device context
  * @np: device node for MCT
- * @int_type: interrupt type, MCT_INT_PPI or MCT_INT_SPI
  * @local_idx: array mapping CPU numbers to local timer indices
  * @nr_local: size of @local_idx array
  */
-static int __init exynos4_timer_interrupts(struct device_node *np,
-					   unsigned int int_type,
+static int __init exynos4_timer_interrupts(struct mct_context *ctx,
+					   struct device_node *np,
 					   const u32 *local_idx,
 					   size_t nr_local)
 {
 	int nr_irqs, i, err, cpu;
 
-	mct_int_type = int_type;
-
 	/* This driver uses only one global timer interrupt */
-	mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
+	ctx->mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
 
 	/*
 	 * Find out the number of local irqs specified. The local
@@ -557,29 +565,30 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 	 * irqs are specified.
 	 */
 	nr_irqs = of_irq_count(np);
-	if (nr_irqs > ARRAY_SIZE(mct_irqs)) {
+	if (nr_irqs > ARRAY_SIZE(ctx->mct_irqs)) {
 		pr_err("exynos-mct: too many (%d) interrupts configured in DT\n",
 			nr_irqs);
-		nr_irqs = ARRAY_SIZE(mct_irqs);
+		nr_irqs = ARRAY_SIZE(ctx->mct_irqs);
 	}
 	for (i = MCT_L0_IRQ; i < nr_irqs; i++)
-		mct_irqs[i] = irq_of_parse_and_map(np, i);
+		ctx->mct_irqs[i] = irq_of_parse_and_map(np, i);
 
 	for_each_possible_cpu(cpu) {
 		struct mct_clock_event_device *mevt =
 		    per_cpu_ptr(&percpu_mct_tick, cpu);
 
+		mevt->ctx = ctx;
 		snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d",
 			 cpu);
 	}
 
-	if (mct_int_type == MCT_INT_PPI) {
+	if (ctx->drvdata->int_type == MCT_INT_PPI) {
 
-		err = request_percpu_irq(mct_irqs[MCT_L0_IRQ],
+		err = request_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ],
 					 exynos4_mct_tick_isr, "MCT",
 					 &percpu_mct_tick);
 		WARN(err, "MCT: can't request IRQ %d (%d)\n",
-		     mct_irqs[MCT_L0_IRQ], err);
+		     ctx->mct_irqs[MCT_L0_IRQ], err);
 	} else {
 		for_each_possible_cpu(cpu) {
 			int mct_irq;
@@ -595,9 +604,9 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 			irq_idx = MCT_L0_IRQ + local_idx[cpu];
 
 			pcpu_mevt->evt.irq = -1;
-			if (irq_idx >= ARRAY_SIZE(mct_irqs))
+			if (irq_idx >= ARRAY_SIZE(ctx->mct_irqs))
 				break;
-			mct_irq = mct_irqs[irq_idx];
+			mct_irq = ctx->mct_irqs[irq_idx];
 
 			irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
 			if (request_irq(mct_irq,
@@ -637,8 +646,8 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 	return 0;
 
 out_irq:
-	if (mct_int_type == MCT_INT_PPI) {
-		free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
+	if (ctx->drvdata->int_type == MCT_INT_PPI) {
+		free_percpu_irq(ctx->mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
 	} else {
 		for_each_possible_cpu(cpu) {
 			struct mct_clock_event_device *pcpu_mevt =
@@ -653,7 +662,7 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
 	return err;
 }
 
-static int __init mct_init_dt(struct device_node *np, unsigned int int_type)
+static int __init mct_init_dt(struct mct_context *ctx, struct device_node *np)
 {
 	bool frc_shared = of_property_read_bool(np, "samsung,frc-shared");
 	u32 local_idx[MCT_NR_LOCAL] = {0};
@@ -679,15 +688,15 @@ static int __init mct_init_dt(struct device_node *np, unsigned int int_type)
 			local_idx[i] = i;
 	}
 
-	ret = exynos4_timer_resources(np);
+	ret = exynos4_timer_resources(ctx, np);
 	if (ret)
 		return ret;
 
-	ret = exynos4_timer_interrupts(np, int_type, local_idx, nr_local);
+	ret = exynos4_timer_interrupts(ctx, np, local_idx, nr_local);
 	if (ret)
 		return ret;
 
-	ret = exynos4_clocksource_init(frc_shared);
+	ret = exynos4_clocksource_init(ctx, frc_shared);
 	if (ret)
 		return ret;
 
@@ -698,18 +707,60 @@ static int __init mct_init_dt(struct device_node *np, unsigned int int_type)
 	if (frc_shared)
 		return 0;
 
-	return exynos4_clockevent_init();
+	ret = exynos4_clockevent_init(ctx);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
+static const struct mct_data exynos4210_mct_data = { .int_type = MCT_INT_SPI, };
+static const struct mct_data exynos4412_mct_data = { .int_type = MCT_INT_PPI, };
 
-static int __init mct_init_spi(struct device_node *np)
-{
-	return mct_init_dt(np, MCT_INT_SPI);
-}
+static const struct of_device_id exynos4_mct_match_table[] = {
+	{ .compatible = "samsung,exynos4210-mct", .data = &exynos4210_mct_data, },
+	{ .compatible = "samsung,exynos4412-mct", .data = &exynos4412_mct_data, },
+	{}
+};
 
-static int __init mct_init_ppi(struct device_node *np)
+/* Note, legacy ARM 32-bit systems depend on the MCT as the only clocksource
+ * which requires this driver to be initialized very early. We need to keep this
+ * special condition until we can transparently support modular and early init
+ * timers.
+ */
+static int __init mct_of_declare_init(struct device_node *np)
 {
-	return mct_init_dt(np, MCT_INT_PPI);
+	struct mct_context *ctx;
+	const struct of_device_id *match;
+	int ret;
+
+	match = of_match_node(exynos4_mct_match_table, np);
+	if (!match || !match->data)
+		return -ENODEV;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->drvdata = match->data;
+
+	ret = mct_init_dt(ctx, np);
+	if (ret)
+		goto out_ctx;
+
+#if defined(CONFIG_ARM)
+	sched_clock_register(exynos4_read_sched_clock, 32, ctx->clk_rate);
+
+	exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
+	exynos4_delay_timer.freq = ctx->clk_rate;
+	register_current_timer_delay(&exynos4_delay_timer);
+#endif
+
+	return 0;
+
+out_ctx:
+	kfree(ctx);
+	return ret;
 }
-TIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi);
-TIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi);
+TIMER_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_of_declare_init);
+TIMER_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_of_declare_init);
-- 
2.52.0.223.gf5cc29aaa4-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ