Linux USB
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Chunfeng Yun" <chunfeng.yun@mediatek.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH v2 4/7] thunderbolt: add platform NHI driver
Date: Tue, 10 Nov 2026 12:15:37 +0000	[thread overview]
Message-ID: <sashiko-outbox-206992@kernel.org> (raw)
In-Reply-To: <20261110114925.722014-5-chunfeng.yun@mediatek.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] thunderbolt: broken system PM when sharing tb_nhi_pm_ops on
  platform_driver
- [Medium] thunderbolt: missing cleanup in nhi_platform_init_irq() and
  tb_nhi_probe()
--

commit 185e80648753aea8ed254f3effc097c624617d73
Author: Chunfeng Yun <chunfeng.yun@mediatek.com>

thunderbolt: add platform NHI driver

This commit adds a platform driver for Thunderbolt/USB4 Native Host Interface
(NHI) controllers integrated as memory-mapped platform devices via Device Tree
or ACPI, including support for an optional dedicated wakeup interrupt.

> diff --git a/drivers/thunderbolt/platform.c b/drivers/thunderbolt/platform.c
> new file mode 100644
> index 0000000000000..3562b6c7ea7db
> --- /dev/null
> +++ b/drivers/thunderbolt/platform.c
> @@ -0,0 +1,172 @@
[ ... ]
> +static int nhi_platform_init(struct tb_nhi *nhi)
> +{
> +	/* avoid device link fail for pcie tunnel */
> +	pm_runtime_set_active(nhi->dev);
> +	pm_runtime_get_noresume(nhi->dev);
> +	pm_runtime_enable(nhi->dev);
> +
> +	device_set_wakeup_capable(nhi->dev, true);
> +	device_enable_async_suspend(nhi->dev);
> +
> +	return 0;
> +}
> +
> +static void nhi_platform_clear_wake_irq(void *dev)
> +{
> +	dev_pm_clear_wake_irq(dev);
> +}
> +
> +static int nhi_platform_init_irq(struct tb_nhi *nhi)
> +{
> +	struct device *dev = nhi->dev;
> +	int ret;
> +
> +	ret = devm_request_irq(dev, nhi->irq, tb_nhi_isr, IRQF_NO_SUSPEND,
> +			       dev_name(dev), nhi);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "request irq failed\n");
> +
> +	if (nhi->wake_irq) {
> +		ret = dev_pm_set_dedicated_wake_irq(dev, nhi->wake_irq);
> +		if (ret) {
> +			return dev_err_probe(dev, ret, "set wake irq %d failed\n", nhi->wake_irq);
> +		}
> +
> +		dev_info(dev, "wake irq %d\n", nhi->wake_irq);
> +
> +		ret = devm_add_action_or_reset(dev, nhi_platform_clear_wake_irq, dev);
> +	}
> +
> +	return ret;
> +}
> +
> +static void nhi_platform_exit(struct tb_nhi *nhi)
> +{
> +	devm_free_irq(nhi->dev, nhi->irq, nhi);
> +	flush_work(&nhi->interrupt_work);
> +
> +	pm_runtime_put_noidle(nhi->dev);
> +	pm_runtime_disable(nhi->dev);
> +	pm_runtime_set_suspended(nhi->dev);
> +}

[Severity: Medium]
Does a probe failure before tb_domain_add() bypass nhi_platform_exit(),
leaving nhi->interrupt_work unflushed and runtime PM enabled on the unbound
device?

In tb_nhi_probe(), tb_nhi_shutdown() is only called if tb_domain_add() fails:

drivers/thunderbolt/nhi.c:tb_nhi_probe() {
	...
	res = nhi->ops->init_interrupts(nhi);
	if (res)
		return dev_err_probe(dev, res, "cannot enable interrupts, aborting\n");

	spin_lock_init(&nhi->lock);

	res = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
	if (res)
		return dev_err_probe(dev, res, "failed to set DMA mask\n");

	if (nhi->ops->init) {
		res = nhi->ops->init(nhi);
		if (res)
			return dev_err_probe(dev, res, "NHI specific init failed\n");
	}

	init_completion(&nhi->domain_released);

	tb = nhi_select_cm(nhi);
	if (!tb)
		return dev_err_probe(dev, -ENODEV,
			"failed to determine connection manager, aborting\n");
	...
}

If dev_pm_set_dedicated_wake_irq() fails in nhi_platform_init_irq(), or if
dma_set_mask_and_coherent() or nhi_select_cm() fails in tb_nhi_probe(),
devres frees nhi->irq, unmaps nhi->iobase, and frees nhi without ever
flushing nhi->interrupt_work, which can cause a use-after-free if
tb_nhi_isr() scheduled the work item.  In addition, if nhi_select_cm() fails
after nhi_platform_init() has run, runtime PM stays enabled with an elevated
usage count, so pm_runtime_reinit() in device_unbind_cleanup() bails out and
a subsequent re-probe warns on unbalanced pm_runtime_enable().

[ ... ]

> +static struct platform_driver nhi_platform_driver = {
> +	.probe = nhi_platform_probe,
> +	.remove = nhi_platform_remove,
> +	.shutdown = nhi_platform_shutdown,
> +	.driver = {
> +		.name = "thunderbolt",
> +		.of_match_table = of_match_ptr(nhi_platform_of_match),
> +		.acpi_match_table = ACPI_PTR(nhi_platform_acpi_match),
> +		.pm = &tb_nhi_pm_ops,
> +	},
> +};

[Severity: High]
Can system suspend and resume run while the platform NHI is runtime-suspended
when using tb_nhi_pm_ops directly on a platform_driver?

On PCI, pci_pm_suspend() runtime-resumes the device before calling the
driver's .suspend and .suspend_noirq callbacks.  Neither the platform bus,
genpd, nor nhi_suspend() does that, and device_wakeup_enable() prevents
direct_complete.  If the controller has autosuspended before system suspend:

1. nhi_suspend_noirq() -> tb_domain_suspend_noirq() runs while the device is
   runtime-suspended (with clocks or power domains gated) and calls
   tb_ctl_stop() on rings already stopped by nhi_runtime_suspend(), triggering
   dev_WARN() in tb_ring_stop().
2. On resume, nhi_resume_noirq() -> tb_domain_resume_noirq() calls
   tb_ctl_start(), touching MMIO while runtime status is still RPM_SUSPENDED
   and queuing ctl->rx_packets[] onto ctl->rx->in_flight.
3. In the complete phase, nhi_complete() sees pm_runtime_suspended(dev) is
    still true and calls pm_runtime_resume(dev) -> nhi_runtime_resume() ->
   tb_ctl_start() a second time:

drivers/thunderbolt/nhi.c:nhi_complete() {
	struct tb *tb = dev_get_drvdata(dev);

	/*
	 * If we were runtime suspended when system suspend started,
	 * schedule runtime resume now. It should bring the domain back
	 * to functional state.
	 */
	if (pm_runtime_suspended(dev))
		pm_runtime_resume(dev);
	else
		tb_domain_complete(tb);
}

The second tb_ctl_start() warns that the rings are already started and calls
tb_ctl_rx_submit() -> __tb_ring_enqueue() -> list_add_tail() on
ctl->rx_packets[] frames that are already linked in ctl->rx->in_flight,
corrupting the ring list.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261110114925.722014-2-chunfeng.yun@mediatek.com?part=4

  reply	other threads:[~2026-11-10 12:15 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 11:48 [PATCH 0/7] thunderbolt: Add support platform NHI driver Chunfeng Yun
2026-11-10 11:48 ` [PATCH v2 1/7] thunderbolt: Prefix NHI core functions with tb_ and tb_ring_ Chunfeng Yun
2026-11-10 11:53   ` sashiko-bot
2026-11-10 12:42   ` Konrad Dybcio
2026-11-11  2:26     ` Chunfeng Yun (云春峰)
2026-11-10 11:48 ` [PATCH v2 2/7] thunderbolt: Move ICM mailbox functions to icm.c and internalize interrupt work Chunfeng Yun
2026-11-10 12:02   ` sashiko-bot
2026-11-10 14:24   ` Mika Westerberg
2026-11-11  2:37     ` Chunfeng Yun (云春峰)
2026-11-10 11:48 ` [PATCH v2 3/7] thunderbolt: Make PCIe NHI support opt-in Chunfeng Yun
2026-11-10 12:09   ` sashiko-bot
2026-11-11 12:17     ` Chunfeng Yun (云春峰)
2026-11-10 11:48 ` [PATCH v2 4/7] thunderbolt: add platform NHI driver Chunfeng Yun
2026-11-10 12:15   ` sashiko-bot [this message]
2026-11-10 12:43   ` Konrad Dybcio
2026-11-11 13:29     ` Chunfeng Yun (云春峰)
2026-11-10 14:37   ` Mika Westerberg
2026-11-10 11:48 ` [PATCH v2 5/7] thunderbolt: increase the lane adapter link-up timeout value Chunfeng Yun
2026-11-10 11:55   ` sashiko-bot
2026-11-12  7:27     ` Chunfeng Yun (云春峰)
2026-11-10 14:39   ` Mika Westerberg
2026-11-12  7:24     ` Chunfeng Yun (云春峰)
2026-11-10 11:48 ` [PATCH v2 6/7] thunderbolt: decouple the waiting time of TB_PORT_UNPLUGGED and TB_PORT_UP Chunfeng Yun
2026-11-10 11:55   ` sashiko-bot
2026-11-10 14:40   ` Mika Westerberg
2026-11-12  8:00     ` Chunfeng Yun (云春峰)
2026-11-10 11:48 ` [PATCH v2 7/7] thunderbolt: prevent pcie tunnel activation/teardown warnings Chunfeng Yun
2026-11-10 12:01   ` sashiko-bot
2026-11-10 14:50   ` Mika Westerberg

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=sashiko-outbox-206992@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=chunfeng.yun@mediatek.com \
    --cc=linux-usb@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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