Skip to content

Commit 7351225

Browse files
committed
mei: vsc: Run event callback from a workqueue
JIRA: https://issues.redhat.com/browse/RHEL-113185 commit de88b02 Author: Hans de Goede <hansg@kernel.org> Date: Mon Jun 23 10:50:50 2025 +0200 mei: vsc: Run event callback from a workqueue The event_notify callback in some cases calls vsc_tp_xfer(), which checks tp->assert_cnt and waits for it through the tp->xfer_wait wait-queue. And tp->assert_cnt is increased and the tp->xfer_wait queue is woken o from the interrupt handler. So the interrupt handler which is running the event callback is waiting for itself to signal that it can continue. This happens to work because the event callback runs from the threaded ISR handler and while that is running the hard ISR handler will still get called a second / third time for further interrupts and it is the hard ISR handler which does the atomic_inc() and wake_up() calls. But having the threaded ISR handler wait for its own interrupt to trigger again is not how a threaded ISR handler is supposed to be used. Move the running of the event callback from a threaded interrupt handler to a workqueue since a threaded ISR should not wait for events from its own interrupt. This is a preparation patch for moving the atomic_inc() and wake_up() calls to the threaded ISR handler, which is necessary to fix a locking issue. Fixes: 566f5ca ("mei: Add transport driver for IVSC device") Signed-off-by: Hans de Goede <hansg@kernel.org> Link: https://lore.kernel.org/r/20250623085052.12347-9-hansg@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Steve Best <sbest@redhat.com>
1 parent 933e51f commit 7351225

File tree

1 file changed

+11
-6
lines changed

1 file changed

+11
-6
lines changed

drivers/misc/mei/vsc-tp.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/platform_device.h>
1919
#include <linux/spi/spi.h>
2020
#include <linux/types.h>
21+
#include <linux/workqueue.h>
2122

2223
#include "vsc-tp.h"
2324

@@ -76,6 +77,7 @@ struct vsc_tp {
7677

7778
atomic_t assert_cnt;
7879
wait_queue_head_t xfer_wait;
80+
struct work_struct event_work;
7981

8082
vsc_tp_event_cb_t event_notify;
8183
void *event_notify_context;
@@ -105,19 +107,19 @@ static irqreturn_t vsc_tp_isr(int irq, void *data)
105107

106108
wake_up(&tp->xfer_wait);
107109

108-
return IRQ_WAKE_THREAD;
110+
schedule_work(&tp->event_work);
111+
112+
return IRQ_HANDLED;
109113
}
110114

111-
static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
115+
static void vsc_tp_event_work(struct work_struct *work)
112116
{
113-
struct vsc_tp *tp = data;
117+
struct vsc_tp *tp = container_of(work, struct vsc_tp, event_work);
114118

115119
guard(mutex)(&tp->event_notify_mutex);
116120

117121
if (tp->event_notify)
118122
tp->event_notify(tp->event_notify_context);
119-
120-
return IRQ_HANDLED;
121123
}
122124

123125
/* wakeup firmware and wait for response */
@@ -495,14 +497,15 @@ static int vsc_tp_probe(struct spi_device *spi)
495497
tp->spi = spi;
496498

497499
irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);
498-
ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr,
500+
ret = request_threaded_irq(spi->irq, vsc_tp_isr, NULL,
499501
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
500502
dev_name(dev), tp);
501503
if (ret)
502504
return ret;
503505

504506
mutex_init(&tp->mutex);
505507
mutex_init(&tp->event_notify_mutex);
508+
INIT_WORK(&tp->event_work, vsc_tp_event_work);
506509

507510
/* only one child acpi device */
508511
ret = acpi_dev_for_each_child(ACPI_COMPANION(dev),
@@ -527,6 +530,7 @@ static int vsc_tp_probe(struct spi_device *spi)
527530
err_destroy_lock:
528531
free_irq(spi->irq, tp);
529532

533+
cancel_work_sync(&tp->event_work);
530534
mutex_destroy(&tp->event_notify_mutex);
531535
mutex_destroy(&tp->mutex);
532536

@@ -542,6 +546,7 @@ static void vsc_tp_remove(struct spi_device *spi)
542546

543547
free_irq(spi->irq, tp);
544548

549+
cancel_work_sync(&tp->event_work);
545550
mutex_destroy(&tp->event_notify_mutex);
546551
mutex_destroy(&tp->mutex);
547552
}

0 commit comments

Comments
 (0)