DMA Engine development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Daniel Byrne" <daniel1.byrne@intel.com>
Cc: dmaengine@vger.kernel.org, vkoul@kernel.org, Frank.Li@kernel.org
Subject: Re: [PATCH 12/17] dmaengine: idxd: hold device commands off while the reset re-creates its interrupts
Date: Mon, 19 Oct 2026 18:19:35 +0000	[thread overview]
Message-ID: <sashiko-outbox-178068@kernel.org> (raw)
In-Reply-To: <20261019150630.4026341-13-daniel1.byrne@intel.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] dmaengine: idxd: idxd_cmd_reset_state() clears hold in idxd_cmd_hold()
- [Medium] dmaengine: idxd: idxd_cmd_hold() skips hold when IDXD_FLAG_CMD_TIMEDOUT is set
--

commit adf023de4cde0518acad5bf473d3a62f589687fb
Author: Daniel Byrne <daniel1.byrne@intel.com>

dmaengine: idxd: hold device commands off while the reset re-creates its interrupts

This commit introduces idxd_cmd_hold() and idxd_cmd_unhold() to wait for
any running device command and hold IDXD_FLAG_CMD_RUNNING across the
interrupt teardown and re-setup window in idxd_pci_probe_alloc() during
reset recovery.

> diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
> index d3b95593a6867..222c201669bdd 100644
> --- a/drivers/dma/idxd/device.c
> +++ b/drivers/dma/idxd/device.c
> @@ -724,6 +724,50 @@ void idxd_cmd_reset_state(struct idxd_device *idxd)
>  	spin_unlock_irqrestore(&idxd->cmd_lock, flags);
>  }
>  
> +/*
> + * Hold device commands off while the re-probe after a reset frees the
> + * interrupts and requests them again. A command whose completion
> + * interrupt comes while the misc vector is gone is never completed, and
> + * its owner would time out and fence the device that was just reset.
> + * The running command, if any, is waited for first: its owner gives up
> + * within its timeout, and the misc vector still takes its interrupt.
> + * RUNNING is then held without an owner, and new commands wait for it
> + * as for any running command. Returns false, holding nothing, when a
> + * command timed out, since commands then fail fast anyway.
> + */
> +bool idxd_cmd_hold(struct idxd_device *idxd, u32 *seq)
> +{
> +	bool held = false;
> +
> +	spin_lock_irq(&idxd->cmd_lock);
> +	wait_event_lock_irq(idxd->cmd_waitq,
> +			    !test_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags) ||
> +			    test_bit(IDXD_FLAG_CMD_TIMEDOUT, &idxd->flags),
> +			    idxd->cmd_lock);
> +	if (!test_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags)) {
> +		__set_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags);
> +		*seq = ++idxd->cmd_seq;
> +		held = true;
> +	}

[Severity: Medium]
What happens in idxd_cmd_hold() if IDXD_FLAG_CMD_TIMEDOUT is set when
wait_event_lock_irq() returns?

When a command times out in idxd_cmd_exec(), IDXD_FLAG_CMD_RUNNING remains
set alongside IDXD_FLAG_CMD_TIMEDOUT. Because IDXD_FLAG_CMD_RUNNING is still
set, idxd_cmd_hold() skips setting held = true and returns false, and
idxd_pci_probe_alloc() proceeds to tear down and re-create interrupts
without a hold.

In idxd_cleanup_interrupts(), idxd_mask_error_interrupts() only masks error
interrupts in GENCTRL and does not mask IDXD_INTC_CMD. If a late command
completion interrupt arrives in idxd_misc_thread() before free_irq()
finishes (or if idxd_cmd_reset_state() runs concurrently):

drivers/dma/idxd/irq.c:idxd_misc_thread() {
    ...
		} else if (test_bit(IDXD_FLAG_CMD_TIMEDOUT, &idxd->flags)) {
			__clear_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags);
			clear_bit(IDXD_FLAG_CMD_TIMEDOUT, &idxd->flags);
			wake_up(&idxd->cmd_waitq);
			dev_warn(dev, "a timed-out device command completed late\n");
		}
    ...
}

Wouldn't this clear both IDXD_FLAG_CMD_RUNNING and IDXD_FLAG_CMD_TIMEDOUT
and wake idxd->cmd_waitq while the MSI-X vectors and misc interrupt are
still being torn down and re-allocated, allowing waiting or newly issued
commands to be submitted while interrupts are absent?

> +	spin_unlock_irq(&idxd->cmd_lock);
> +	return held;
> +}
> +
> +/*
> + * End a hold taken by idxd_cmd_hold(). A halt's recovery may have
> + * forgotten the hold meanwhile and let another command run, which then
> + * has an owner or a newer sequence number, and its state is left alone.
> + */
> +void idxd_cmd_unhold(struct idxd_device *idxd, u32 seq)
> +{
> +	spin_lock_irq(&idxd->cmd_lock);
> +	if (idxd->cmd_seq == seq && !idxd->cmd_done) {
> +		__clear_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags);
> +		wake_up(&idxd->cmd_waitq);
> +	}
> +	spin_unlock_irq(&idxd->cmd_lock);
> +}

[Severity: High]
If a concurrent halt recovery in idxd_device_reinit() forgets the hold
while idxd_pci_probe_alloc() is between idxd_cleanup_interrupts() and
idxd_setup_interrupts(), won't the command started after
idxd_cmd_reset_state() still lose its completion interrupt and time out?

Specifically, idxd_cmd_hold() overloads IDXD_FLAG_CMD_RUNNING to block
new commands, while idxd_cmd_reset_state() unconditionally clears it:

drivers/dma/idxd/device.c:idxd_cmd_reset_state() {
    ...
	__clear_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags);
	clear_bit(IDXD_FLAG_CMD_TIMEDOUT, &idxd->flags);
	wake_up(&idxd->cmd_waitq);
    ...
}

And idxd_device_reinit() immediately issues a reset command right after
resetting the command state:

drivers/dma/idxd/irq.c:idxd_device_reinit() {
    ...
	idxd_cmd_reset_state(idxd);
	rc = idxd_device_reset(idxd);
    ...
}

If idxd_device_reinit() runs while the misc interrupt and MSI-X vectors
are freed during the reset re-probe in idxd_pci_probe_alloc(),
idxd_cmd_reset_state() clears IDXD_FLAG_CMD_RUNNING and wakes
idxd->cmd_waitq. Because pci_restore_state() in idxd_reset_done() has
already cleared the hardware halt state, idxd_device_reset() ->
idxd_cmd_exec() (along with any woken waiters) will submit a command while
the misc interrupt is torn down.

Although idxd_cmd_unhold() avoids clobbering the new command's state when
idxd->cmd_seq != seq, hasn't that command already been submitted while
interrupts were absent, causing it to lose its completion interrupt, time
out after 30 seconds, and fence the device?

[ ... ]

> diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
> index a037a6e763622..312b4670b3e82 100644
> --- a/drivers/dma/idxd/init.c
> +++ b/drivers/dma/idxd/init.c
> @@ -1212,6 +1212,14 @@ int idxd_pci_probe_alloc(struct idxd_device *idxd, struct pci_dev *pdev,
>  	}
>  
>  	if (!alloc_idxd) {
> +		bool held;
> +		u32 seq;
> +
> +		/*
> +		 * Commands complete through the misc interrupt, which is
> +		 * gone until it is requested again.
> +		 */
> +		held = idxd_cmd_hold(idxd, &seq);
>  		/* Release interrupts in the IDXD device. */
>  		idxd_cleanup_interrupts(idxd);
>  
> @@ -1219,6 +1227,8 @@ int idxd_pci_probe_alloc(struct idxd_device *idxd, struct pci_dev *pdev,
>  		rc = idxd_setup_interrupts(idxd);
>  		if (rc)
>  			dev_warn(dev, "IDXD interrupts failed to setup\n");
> +		if (held)
> +			idxd_cmd_unhold(idxd, seq);
>  	}
>  
>  	dev_info(&pdev->dev, "Intel(R) Accelerator Device (v%x)\n",

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019150630.4026341-1-daniel1.byrne@intel.com?part=12

  reply	other threads:[~2026-10-19 18:19 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-19 15:06 [PATCH 00/17] [PATCH 00/17] dmaengine: idxd: fixes found by an in-kernel polling client Daniel Byrne
2026-10-19 15:06 ` [PATCH 01/17] dmaengine: idxd: don't queue EVL fault work for kernel WQs Daniel Byrne
2026-10-19 15:06 ` [PATCH 02/17] dmaengine: idxd: detach the user fault workqueue under the event log lock Daniel Byrne
2026-10-19 15:06 ` [PATCH 03/17] dmaengine: idxd: refuse a memcpy longer than the WQ max transfer size Daniel Byrne
2026-10-19 21:19   ` Frank Li
2026-10-19 15:06 ` [PATCH 04/17] dmaengine: idxd: list a new channel only once it is complete Daniel Byrne
2026-10-19 15:06 ` [PATCH 05/17] dmaengine: idxd: unbind the device driver before its work queues go away Daniel Byrne
2026-10-19 15:06 ` [PATCH 06/17] dmaengine: idxd: keep the interrupt handle across terminate_all Daniel Byrne
2026-10-19 15:06 ` [PATCH 07/17] dmaengine: idxd: bound device command waits and fail fast after a timeout Daniel Byrne
2026-10-19 17:05   ` sashiko-bot
2026-10-19 15:06 ` [PATCH 08/17] dmaengine: idxd: compare the device disable status code whole Daniel Byrne
2026-10-19 15:06 ` [PATCH 09/17] dmaengine: idxd: quarantine terminate_all's descriptor slots until the device has drained Daniel Byrne
2026-10-19 17:26   ` sashiko-bot
2026-10-19 15:06 ` [PATCH 10/17] dmaengine: idxd: return -ETIMEDOUT from drains and resets and leak what the device may still write Daniel Byrne
2026-10-19 17:50   ` sashiko-bot
2026-10-19 15:06 ` [PATCH 11/17] dmaengine: idxd: disable the device before its work queues are unregistered Daniel Byrne
2026-10-19 18:09   ` sashiko-bot
2026-10-19 15:06 ` [PATCH 12/17] dmaengine: idxd: hold device commands off while the reset re-creates its interrupts Daniel Byrne
2026-10-19 18:19   ` sashiko-bot [this message]
2026-10-19 15:06 ` [PATCH 13/17] dmaengine: idxd: fix the double free of a descriptor whose submission failed Daniel Byrne
2026-10-19 15:06 ` [PATCH 14/17] dmaengine: idxd: complete an iaa_crypto descriptor through its own driver on abort and flush Daniel Byrne
2026-10-19 18:56   ` sashiko-bot
2026-10-19 15:06 ` [PATCH 15/17] dmaengine: idxd: flush the work queues on every halt type Daniel Byrne
2026-10-19 19:17   ` sashiko-bot
2026-10-19 15:06 ` [PATCH 16/17] dmaengine: idxd: keep client callbacks on a halt flush and cancel resubmissions after a terminate Daniel Byrne
2026-10-19 19:36   ` sashiko-bot
2026-10-19 15:06 ` [PATCH 17/17] dmaengine: idxd: run the interrupt-handle revoke under the queue lock Daniel Byrne
2026-10-19 19:53   ` sashiko-bot
2026-10-19 19:09 ` [PATCH 00/17] [PATCH 00/17] dmaengine: idxd: fixes found by an in-kernel polling client Frank Li

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-178068@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=daniel1.byrne@intel.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vkoul@kernel.org \
    /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