Messages in this thread Patch in this message |  | | From | Eli Billauer <> | | Subject | [PATCH v5 7/7] char: xillybus: Ignore and report unsolicited interrupts | | Date | Wed, 5 Aug 2026 13:13:37 +0200 |
| |
During initialization, the hardware should issue interrupts only in response to requests from the host. Ignore and log unexpected interrupts, as these indicate misbehaving hardware, and return IRQ_NONE when the interrupt appears to be spurious.
In the same spirit, in xilly_quiesce(), assign endpoint->num_channels = 0 before allowing the ISR, in order to expose whether the hardware incorrectly sends messages related to data channels during shutdown.
Assisted-by: Deepseek:v4-pro Kimi:K2.6 ChatGPT:GPT-5.5 Claude:Sonnet-4.6 Assisted-by: Sashiko-0.2.5:gemini-3.1-pro-preview Signed-off-by: Eli Billauer <eli.billauer@gmail.com> ---
Notes: Changelog: ========= No change on v4->v5. Changes v3->v4: -- Return IRQ_NONE if the interrupt is considered spurious, following Sashiko's remark + add attribution to Sashiko. Changes v2->v3: -- Add Assisted-by tag to description No change on v1->v2.
drivers/char/xillybus/xillybus.h | 3 ++ drivers/char/xillybus/xillybus_core.c | 47 ++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/char/xillybus/xillybus.h b/drivers/char/xillybus/xillybus.h index 51de7cbc579e..98c7ac4dd1f9 100644 --- a/drivers/char/xillybus/xillybus.h +++ b/drivers/char/xillybus/xillybus.h @@ -94,6 +94,9 @@ struct xilly_endpoint { __iomem void *registers; int fatal_error; + bool allow_isr; + spinlock_t allow_isr_lock; + struct mutex register_mutex; wait_queue_head_t ep_wait; diff --git a/drivers/char/xillybus/xillybus_core.c b/drivers/char/xillybus/xillybus_core.c index fc489908c40c..b35d8eda15c9 100644 --- a/drivers/char/xillybus/xillybus_core.c +++ b/drivers/char/xillybus/xillybus_core.c @@ -72,6 +72,8 @@ static struct workqueue_struct *xillybus_wq; * * rd_spinlock does the same with rd_*_buf_idx, rd_empty and end_offset. * + * allow_isr_lock protects allow_isr. + * * register_mutex is endpoint-specific, and is held when non-atomic * register operations are performed. wr_mutex and rd_mutex may be * held when register_mutex is taken, but none of the spinlocks. Note that @@ -84,7 +86,8 @@ static struct workqueue_struct *xillybus_wq; * Only interruptible blocking is allowed on mutexes and wait queues. * * All in all, the locking order goes (with skips allowed, of course): - * wr_mutex -> rd_mutex -> register_mutex -> wr_spinlock -> rd_spinlock + * wr_mutex -> rd_mutex -> register_mutex -> + * allow_isr_lock -> wr_spinlock -> rd_spinlock */ static void malformed_message(struct xilly_endpoint *endpoint, u32 *buf) @@ -119,6 +122,13 @@ irqreturn_t xillybus_isr(int irq, void *data) unsigned int msg_channel, msg_bufno, msg_data, msg_dir; struct xilly_channel *channel; + guard(spinlock)(&ep->allow_isr_lock); + + if (!ep->allow_isr) { + dev_err_ratelimited(ep->dev, "Unexpected interrupt! Something is wrong with the hardware.\n"); + return IRQ_NONE; + } + buf = ep->msgbuf_addr; buf_size = ep->msg_buf_size/sizeof(u32); @@ -137,6 +147,7 @@ irqreturn_t xillybus_isr(int irq, void *data) if (++ep->failed_messages > 10) { dev_err(ep->dev, "Lost sync with interrupt messages. Stopping.\n"); + return IRQ_NONE; } else { dma_sync_single_for_device(ep->dev, ep->msgbuf_dma_addr, @@ -283,6 +294,19 @@ irqreturn_t xillybus_isr(int irq, void *data) } EXPORT_SYMBOL(xillybus_isr); +/* + * xilly_allow_isr() is similar to enabling / disabling the interrupt, + * with the difference that if an interrupt is issued while ep->allow_isr + * is false, this is visible in the kernel log. + */ + +static void xilly_allow_isr(struct xilly_endpoint *ep, bool newstate) +{ + guard(spinlock_irqsave)(&ep->allow_isr_lock); + + ep->allow_isr = newstate; +} + /* * A few trivial memory management functions. * NOTE: These functions are used only on probe and remove, and therefore @@ -651,6 +675,8 @@ static int xilly_obtain_idt(struct xilly_endpoint *endpoint) channel->wr_sleepy = 1; + xilly_allow_isr(endpoint, true); + iowrite32(1 | (3 << 24), /* Opcode 3 for channel 0 = Send IDT */ endpoint->registers + fpga_buf_ctrl_reg); @@ -659,6 +685,8 @@ static int xilly_obtain_idt(struct xilly_endpoint *endpoint) (!channel->wr_sleepy), XILLY_TIMEOUT); + xilly_allow_isr(endpoint, false); + if (t <= 0) { dev_err(endpoint->dev, "Failed to obtain IDT. Aborting.\n"); @@ -1837,6 +1865,9 @@ struct xilly_endpoint *xillybus_init_endpoint(struct device *dev) endpoint->failed_messages = 0; endpoint->fatal_error = 0; + endpoint->allow_isr = false; + spin_lock_init(&endpoint->allow_isr_lock); + init_waitqueue_head(&endpoint->ep_wait); mutex_init(&endpoint->register_mutex); @@ -1849,6 +1880,9 @@ static int xilly_quiesce(struct xilly_endpoint *endpoint) long t; endpoint->idtlen = -1; + endpoint->num_channels = 0; + + xilly_allow_isr(endpoint, true); iowrite32((u32) (endpoint->dma_using_dac & 0x0001), endpoint->registers + fpga_dma_control_reg); @@ -1856,6 +1890,9 @@ static int xilly_quiesce(struct xilly_endpoint *endpoint) t = wait_event_interruptible_timeout(endpoint->ep_wait, (endpoint->idtlen >= 0), XILLY_TIMEOUT); + + xilly_allow_isr(endpoint, false); + if (t <= 0) { dev_err(endpoint->dev, "Failed to quiesce the device on exit.\n"); @@ -1909,6 +1946,8 @@ int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint) endpoint->idtlen = -1; + xilly_allow_isr(endpoint, true); + /* * Set DMA 32/64 bit mode, quiesce the device (?!) and get IDT * buffer size. @@ -1919,6 +1958,9 @@ int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint) t = wait_event_interruptible_timeout(endpoint->ep_wait, (endpoint->idtlen >= 0), XILLY_TIMEOUT); + + xilly_allow_isr(endpoint, false); + if (t <= 0) { dev_err(endpoint->dev, "No response from FPGA. Aborting.\n"); return -ENODEV; @@ -1945,6 +1987,7 @@ int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint) if (rc) goto failed_idt; + /* xilly_obtain_idt() allows and then disallows the ISR */ rc = xilly_obtain_idt(endpoint); if (rc) goto failed_idt; @@ -1963,6 +2006,8 @@ int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint) if (rc) goto failed_idt; + xilly_allow_isr(endpoint, true); + rc = xillybus_init_chrdev(dev, &xillybus_fops, endpoint->owner, endpoint, idt_handle.names, -- 2.34.1
|  |