devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: Xingyu Wu <xingyu.wu@starfivetech.com>,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	Emil Renner Berthing <emil.renner.berthing@canonical.com>,
	Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Cc: linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
	Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	Walker Chen <walker.chen@starfivetech.com>,
	Xingyu Wu <xingyu.wu@starfivetech.com>,
	linux-kernel@vger.kernel.org, Conor Dooley <conor@kernel.org>
Subject: Re: [PATCH v8 2/3] clocksource: Add JH7110 timer driver
Date: Tue, 27 Feb 2024 17:32:54 +0100	[thread overview]
Message-ID: <877cipamvd.ffs@tglx> (raw)
In-Reply-To: <20231219145402.7879-3-xingyu.wu@starfivetech.com>

On Tue, Dec 19 2023 at 22:54, Xingyu Wu wrote:
> +
> +struct jh7110_clkevt {
> +	struct clk *clk;
> +	struct reset_control *rst;
> +	void __iomem *base;
> +	u32 reload_val;
> +	int irq;
> +	char name[sizeof("jh7110-timer.chX")];
> +};
> +
> +struct jh7110_timer_priv {
> +	struct reset_control *prst;
> +	struct device *dev;
> +	struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX];
> +};

Please format your data structures according to documentation:

https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#struct-declarations-and-initializers

> +/* IRQ handler for the timer */
> +static irqreturn_t jh7110_timer_interrupt(int irq, void *data)
> +{
> +	struct clock_event_device *evt = data;
> +	struct jh7110_clkevt *clkevt = &jh7110_timer_info.clkevt[0];
> +	u8 cpu_id = smp_processor_id();
> +	u32 reg = readl(clkevt->base + JH7110_TIMER_INT_STATUS);

https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#variable-declarations

> +	/* Check interrupt status and channel(cpu) ID */
> +	if (!(reg & BIT(cpu_id)))
> +		return IRQ_NONE;
> +
> +	clkevt = &jh7110_timer_info.clkevt[cpu_id];
> +	writel(JH7110_TIMER_INT_CLR_ENA, (clkevt->base + JH7110_TIMER_INT_CLR));
> +
> +	if (evt->event_handler)
> +		evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int jh7110_timer_set_periodic(struct clock_event_device *evt)
> +{
> +	struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT;
> +
> +	writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL);
> +	return 0;
> +}
> +
> +static int jh7110_timer_set_oneshot(struct clock_event_device *evt)
> +{
> +	struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT;
> +
> +	writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL);
> +	return 0;
> +}
> +
> +static int jh7110_timer_set_next_event(unsigned long next,
> +				       struct clock_event_device *evt)
> +{
> +	struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT;
> +
> +	writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL);
> +	writel(next, clkevt->base + JH7110_TIMER_LOAD);
> +
> +	return jh7110_timer_start(clkevt);
> +}
> +
> +static DEFINE_PER_CPU(struct clock_event_device, jh7110_clock_event) = {
> +	.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +	.rating = JH7110_CLOCKEVENT_RATING,
> +	.set_state_shutdown = jh7110_timer_shutdown,
> +	.set_state_periodic = jh7110_timer_set_periodic,
> +	.set_state_oneshot = jh7110_timer_set_oneshot,
> +	.set_state_oneshot_stopped = jh7110_timer_shutdown,
> +	.tick_resume = jh7110_timer_tick_resume,
> +	.set_next_event = jh7110_timer_set_next_event,
> +	.suspend = jh7110_timer_suspend,
> +	.resume = jh7110_timer_resume,
> +};

See formatting rules.

> +static int jh7110_timer_starting_cpu(unsigned int cpu)
> +{
> +	struct clock_event_device *evt = per_cpu_ptr(&jh7110_clock_event, cpu);
> +	struct jh7110_timer_priv *priv = &jh7110_timer_info;
> +	int ret;
> +	u32 rate;
> +
> +	if (cpu >= JH7110_TIMER_CH_MAX)
> +		return -ENOMEM;
> +
> +	ret = clk_prepare_enable(priv->clkevt[cpu].clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = reset_control_deassert(priv->clkevt[cpu].rst);
> +	if (ret)
> +		return ret;
> +
> +	rate = clk_get_rate(priv->clkevt[cpu].clk);
> +	evt->cpumask = cpumask_of(cpu);
> +	evt->irq = priv->clkevt[cpu].irq;
> +	evt->name = priv->clkevt[cpu].name;
> +	clockevents_config_and_register(evt, rate, JH7110_TIMER_MIN_TICKS,
> +					JH7110_TIMER_MAX_TICKS);
> +
> +	ret = devm_request_irq(priv->dev, evt->irq, jh7110_timer_interrupt,
> +			       IRQF_TIMER | IRQF_IRQPOLL,
> +			       evt->name, evt);

How is this all supposed to work from a CPU hotplug state callback which
runs in the early bringup phase with interrupts disabled? clk_prepare()
which is invoked from clk_prepare_enable() can sleep and
devm_request_irq() can sleep too.

Did you ever test this with the required debug config options enabled?

  https://www.kernel.org/doc/html/latest/process/submit-checklist.html

Obviously not.

> +	if (ret)
> +		return ret;
> +
> +	ret = irq_set_affinity(evt->irq, cpumask_of(cpu));
> +	if (ret)
> +		return ret;
> +	/* Use one-shot mode */
> +	writel(JH7110_TIMER_MODE_SINGLE, (priv->clkevt[cpu].base + JH7110_TIMER_CTL));
> +
> +	return jh7110_timer_start(&priv->clkevt[cpu]);
> +}
> +
> +static void jh7110_timer_release(void *data)
> +{
> +	struct jh7110_timer_priv *priv = data;
> +	int i;
> +
> +	for (i = 0; i < JH7110_TIMER_CH_MAX; i++) {
> +		/* Disable each channel of timer */
> +		if (priv->clkevt[i].base)
> +			writel(JH7110_TIMER_DIS, priv->clkevt[i].base + JH7110_TIMER_ENABLE);
> +
> +		/* Avoid no initialization in the loop of the probe */
> +		if (!IS_ERR_OR_NULL(priv->clkevt[i].rst))
> +			reset_control_assert(priv->clkevt[i].rst);
> +
> +		if (!IS_ERR_OR_NULL(priv->clkevt[i].clk))
> +			clk_disable_unprepare(priv->clkevt[i].clk);

Same problem. And of course this does not undo the other steps of
jh7110_timer_starting_cpu() so if you offline a CPU and then online it
again the callback will fail because the clockevent is already
registered and the interrupt requested. Clearly untested too.

Thanks,

        tglx



  parent reply	other threads:[~2024-02-27 16:32 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-19 14:53 [PATCH v8 0/3] Add timer driver for StarFive JH7110 RISC-V SoC Xingyu Wu
2023-12-19 14:54 ` [PATCH v8 1/3] dt-bindings: timer: Add timer for StarFive JH7110 SoC Xingyu Wu
2023-12-19 14:54 ` [PATCH v8 2/3] clocksource: Add JH7110 timer driver Xingyu Wu
2023-12-20 13:59   ` Emil Renner Berthing
2023-12-21  1:50     ` Xingyu Wu
2024-02-27 16:32   ` Thomas Gleixner [this message]
2023-12-19 14:54 ` [PATCH v8 3/3] riscv: dts: jh7110: starfive: Add timer node Xingyu Wu
2024-02-27  1:26 ` 回复: [PATCH v8 0/3] Add timer driver for StarFive JH7110 RISC-V SoC Xingyu Wu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=877cipamvd.ffs@tglx \
    --to=tglx@linutronix.de \
    --cc=aou@eecs.berkeley.edu \
    --cc=christophe.jaillet@wanadoo.fr \
    --cc=conor@kernel.org \
    --cc=daniel.lezcano@linaro.org \
    --cc=devicetree@vger.kernel.org \
    --cc=emil.renner.berthing@canonical.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=p.zabel@pengutronix.de \
    --cc=palmer@dabbelt.com \
    --cc=paul.walmsley@sifive.com \
    --cc=robh+dt@kernel.org \
    --cc=walker.chen@starfivetech.com \
    --cc=xingyu.wu@starfivetech.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).