Skip to content

Commit f6085a9

Browse files
Sakari Ailusgregkh
authored andcommitted
mei: vsc: Unregister interrupt handler for system suspend
Unregister the MEI VSC interrupt handler before system suspend and re-register it at system resume time. This mirrors implementation of other MEI devices. This patch fixes the bug that causes continuous stream of MEI VSC errors after system resume. Fixes: 386a766 ("mei: Add MEI hardware support for IVSC device") Cc: [email protected] # for 6.8 Reported-by: Dominik Brodowski <[email protected]> Signed-off-by: Wentong Wu <[email protected]> Signed-off-by: Sakari Ailus <[email protected]> Acked-by: Tomas Winkler <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e3dc66d commit f6085a9

File tree

3 files changed

+78
-26
lines changed

3 files changed

+78
-26
lines changed

drivers/misc/mei/platform-vsc.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,25 +400,40 @@ static void mei_vsc_remove(struct platform_device *pdev)
400400
static int mei_vsc_suspend(struct device *dev)
401401
{
402402
struct mei_device *mei_dev = dev_get_drvdata(dev);
403+
struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
403404

404405
mei_stop(mei_dev);
405406

407+
mei_disable_interrupts(mei_dev);
408+
409+
vsc_tp_free_irq(hw->tp);
410+
406411
return 0;
407412
}
408413

409414
static int mei_vsc_resume(struct device *dev)
410415
{
411416
struct mei_device *mei_dev = dev_get_drvdata(dev);
417+
struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
412418
int ret;
413419

414-
ret = mei_restart(mei_dev);
420+
ret = vsc_tp_request_irq(hw->tp);
415421
if (ret)
416422
return ret;
417423

424+
ret = mei_restart(mei_dev);
425+
if (ret)
426+
goto err_free;
427+
418428
/* start timer if stopped in suspend */
419429
schedule_delayed_work(&mei_dev->timer_work, HZ);
420430

421431
return 0;
432+
433+
err_free:
434+
vsc_tp_free_irq(hw->tp);
435+
436+
return ret;
422437
}
423438

424439
static DEFINE_SIMPLE_DEV_PM_OPS(mei_vsc_pm_ops, mei_vsc_suspend, mei_vsc_resume);

drivers/misc/mei/vsc-tp.c

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,27 @@ static const struct acpi_gpio_mapping vsc_tp_acpi_gpios[] = {
9494
{}
9595
};
9696

97+
static irqreturn_t vsc_tp_isr(int irq, void *data)
98+
{
99+
struct vsc_tp *tp = data;
100+
101+
atomic_inc(&tp->assert_cnt);
102+
103+
wake_up(&tp->xfer_wait);
104+
105+
return IRQ_WAKE_THREAD;
106+
}
107+
108+
static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
109+
{
110+
struct vsc_tp *tp = data;
111+
112+
if (tp->event_notify)
113+
tp->event_notify(tp->event_notify_context);
114+
115+
return IRQ_HANDLED;
116+
}
117+
97118
/* wakeup firmware and wait for response */
98119
static int vsc_tp_wakeup_request(struct vsc_tp *tp)
99120
{
@@ -383,6 +404,37 @@ int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb,
383404
}
384405
EXPORT_SYMBOL_NS_GPL(vsc_tp_register_event_cb, VSC_TP);
385406

407+
/**
408+
* vsc_tp_request_irq - request irq for vsc_tp device
409+
* @tp: vsc_tp device handle
410+
*/
411+
int vsc_tp_request_irq(struct vsc_tp *tp)
412+
{
413+
struct spi_device *spi = tp->spi;
414+
struct device *dev = &spi->dev;
415+
int ret;
416+
417+
irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);
418+
ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr,
419+
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
420+
dev_name(dev), tp);
421+
if (ret)
422+
return ret;
423+
424+
return 0;
425+
}
426+
EXPORT_SYMBOL_NS_GPL(vsc_tp_request_irq, VSC_TP);
427+
428+
/**
429+
* vsc_tp_free_irq - free irq for vsc_tp device
430+
* @tp: vsc_tp device handle
431+
*/
432+
void vsc_tp_free_irq(struct vsc_tp *tp)
433+
{
434+
free_irq(tp->spi->irq, tp);
435+
}
436+
EXPORT_SYMBOL_NS_GPL(vsc_tp_free_irq, VSC_TP);
437+
386438
/**
387439
* vsc_tp_intr_synchronize - synchronize vsc_tp interrupt
388440
* @tp: vsc_tp device handle
@@ -413,27 +465,6 @@ void vsc_tp_intr_disable(struct vsc_tp *tp)
413465
}
414466
EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_disable, VSC_TP);
415467

416-
static irqreturn_t vsc_tp_isr(int irq, void *data)
417-
{
418-
struct vsc_tp *tp = data;
419-
420-
atomic_inc(&tp->assert_cnt);
421-
422-
wake_up(&tp->xfer_wait);
423-
424-
return IRQ_WAKE_THREAD;
425-
}
426-
427-
static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
428-
{
429-
struct vsc_tp *tp = data;
430-
431-
if (tp->event_notify)
432-
tp->event_notify(tp->event_notify_context);
433-
434-
return IRQ_HANDLED;
435-
}
436-
437468
static int vsc_tp_match_any(struct acpi_device *adev, void *data)
438469
{
439470
struct acpi_device **__adev = data;
@@ -490,10 +521,9 @@ static int vsc_tp_probe(struct spi_device *spi)
490521
tp->spi = spi;
491522

492523
irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);
493-
ret = devm_request_threaded_irq(dev, spi->irq, vsc_tp_isr,
494-
vsc_tp_thread_isr,
495-
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
496-
dev_name(dev), tp);
524+
ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr,
525+
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
526+
dev_name(dev), tp);
497527
if (ret)
498528
return ret;
499529

@@ -522,6 +552,8 @@ static int vsc_tp_probe(struct spi_device *spi)
522552
err_destroy_lock:
523553
mutex_destroy(&tp->mutex);
524554

555+
free_irq(spi->irq, tp);
556+
525557
return ret;
526558
}
527559

@@ -532,6 +564,8 @@ static void vsc_tp_remove(struct spi_device *spi)
532564
platform_device_unregister(tp->pdev);
533565

534566
mutex_destroy(&tp->mutex);
567+
568+
free_irq(spi->irq, tp);
535569
}
536570

537571
static const struct acpi_device_id vsc_tp_acpi_ids[] = {

drivers/misc/mei/vsc-tp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ int vsc_tp_xfer(struct vsc_tp *tp, u8 cmd, const void *obuf, size_t olen,
3737
int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb,
3838
void *context);
3939

40+
int vsc_tp_request_irq(struct vsc_tp *tp);
41+
void vsc_tp_free_irq(struct vsc_tp *tp);
42+
4043
void vsc_tp_intr_enable(struct vsc_tp *tp);
4144
void vsc_tp_intr_disable(struct vsc_tp *tp);
4245
void vsc_tp_intr_synchronize(struct vsc_tp *tp);

0 commit comments

Comments
 (0)