thunderbolt: Make interrupt optional for rings

For some use-cases it does make sense to poll the rings directly instead
of relying on the interrupt. For this reason add a new flag RING_FLAG_NO_INTERRUPT
that can be used to allocate ring in polled mode.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
Mika Westerberg 2026-06-18 07:22:49 +03:00
parent 42bc693533
commit f5cb175ed7
2 changed files with 23 additions and 6 deletions

View File

@ -235,6 +235,12 @@ static void ring_write_descriptors(struct tb_ring *ring)
{
struct ring_frame *frame, *n;
struct ring_desc *descriptor;
u32 flags;
flags = RING_DESC_POSTED;
if (!(ring->flags & RING_FLAG_NO_INTERRUPT))
flags |= RING_DESC_INTERRUPT;
list_for_each_entry_safe(frame, n, &ring->queue, list) {
if (ring_full(ring))
break;
@ -242,7 +248,7 @@ static void ring_write_descriptors(struct tb_ring *ring)
descriptor = &ring->descriptors[ring->head];
descriptor->phys = frame->buffer_phy;
descriptor->time = 0;
descriptor->flags = RING_DESC_POSTED | RING_DESC_INTERRUPT;
descriptor->flags = flags;
if (ring->is_tx) {
descriptor->length = frame->size;
descriptor->eof = frame->eof;
@ -339,8 +345,9 @@ EXPORT_SYMBOL_GPL(__tb_ring_enqueue);
* @ring: Ring to poll
*
* This function can be called when @start_poll callback of the @ring
* has been called. It will read one completed frame from the ring and
* return it to the caller.
* has been called or the ring is created with %RING_FLAG_NO_INTERRUPT.
* It will read one completed frame from the ring and return it to the
* caller.
*
* Return: Pointer to &struct ring_frame, %NULL if there is no more
* completed frames.
@ -538,6 +545,12 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
dev_dbg(nhi->dev, "allocating %s ring %d of size %d\n",
transmit ? "TX" : "RX", hop, size);
if ((flags & RING_FLAG_NO_INTERRUPT) && start_poll) {
dev_WARN(nhi->dev,
"start_poll() and NO_INTERRUPT cannot be used at the same time\n");
return NULL;
}
ring = kzalloc_obj(*ring);
if (!ring)
return NULL;
@ -568,7 +581,7 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
if (!ring->descriptors)
goto err_free_ring;
if (nhi->ops->request_ring_irq) {
if (!(flags & RING_FLAG_NO_INTERRUPT) && nhi->ops->request_ring_irq) {
if (nhi->ops->request_ring_irq(ring, flags & RING_FLAG_NO_SUSPEND))
goto err_free_descs;
}
@ -701,7 +714,8 @@ void tb_ring_start(struct tb_ring *ring)
ring_iowrite32options(ring, flags, 0);
}
ring_interrupt_active(ring, true);
if (!(ring->flags & RING_FLAG_NO_INTERRUPT))
ring_interrupt_active(ring, true);
ring->running = true;
err:
spin_unlock(&ring->lock);
@ -761,7 +775,8 @@ void tb_ring_stop(struct tb_ring *ring)
RING_TYPE(ring), ring->hop);
goto err;
}
ring_interrupt_active(ring, false);
if (!(ring->flags & RING_FLAG_NO_INTERRUPT))
ring_interrupt_active(ring, false);
ring_iowrite32options(ring, 0, 0);
ring_iowrite64desc(ring, 0, 0);

View File

@ -598,6 +598,8 @@ struct tb_ring {
#define RING_FLAG_FRAME BIT(1)
/* Enable end-to-end flow control */
#define RING_FLAG_E2E BIT(2)
/* Do not enable interrupt for the ring */
#define RING_FLAG_NO_INTERRUPT BIT(3)
struct ring_frame;
typedef void (*ring_cb)(struct tb_ring *, struct ring_frame *, bool canceled);