]> Git Repo - J-linux.git/commitdiff
mei: vsc: Unregister interrupt handler for system suspend
authorSakari Ailus <[email protected]>
Wed, 3 Apr 2024 05:13:41 +0000 (13:13 +0800)
committerGreg Kroah-Hartman <[email protected]>
Thu, 11 Apr 2024 13:15:53 +0000 (15:15 +0200)
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: 386a766c4169 ("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]>
drivers/misc/mei/platform-vsc.c
drivers/misc/mei/vsc-tp.c
drivers/misc/mei/vsc-tp.h

index 6c9f00bcb94b1857588b3bc6a0ada02421d9f87a..b543e6b9f3cfd6542e744854fa6d20c1cbe7b216 100644 (file)
@@ -400,25 +400,40 @@ static void mei_vsc_remove(struct platform_device *pdev)
 static int mei_vsc_suspend(struct device *dev)
 {
        struct mei_device *mei_dev = dev_get_drvdata(dev);
+       struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
 
        mei_stop(mei_dev);
 
+       mei_disable_interrupts(mei_dev);
+
+       vsc_tp_free_irq(hw->tp);
+
        return 0;
 }
 
 static int mei_vsc_resume(struct device *dev)
 {
        struct mei_device *mei_dev = dev_get_drvdata(dev);
+       struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
        int ret;
 
-       ret = mei_restart(mei_dev);
+       ret = vsc_tp_request_irq(hw->tp);
        if (ret)
                return ret;
 
+       ret = mei_restart(mei_dev);
+       if (ret)
+               goto err_free;
+
        /* start timer if stopped in suspend */
        schedule_delayed_work(&mei_dev->timer_work, HZ);
 
        return 0;
+
+err_free:
+       vsc_tp_free_irq(hw->tp);
+
+       return ret;
 }
 
 static DEFINE_SIMPLE_DEV_PM_OPS(mei_vsc_pm_ops, mei_vsc_suspend, mei_vsc_resume);
index 968a92a7425df36a6c5ee4bdfa16250ca7bd5d11..e6a98dba8a735ec88787d7c8577879b80b323bf7 100644 (file)
@@ -94,6 +94,27 @@ static const struct acpi_gpio_mapping vsc_tp_acpi_gpios[] = {
        {}
 };
 
+static irqreturn_t vsc_tp_isr(int irq, void *data)
+{
+       struct vsc_tp *tp = data;
+
+       atomic_inc(&tp->assert_cnt);
+
+       wake_up(&tp->xfer_wait);
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
+{
+       struct vsc_tp *tp = data;
+
+       if (tp->event_notify)
+               tp->event_notify(tp->event_notify_context);
+
+       return IRQ_HANDLED;
+}
+
 /* wakeup firmware and wait for response */
 static int vsc_tp_wakeup_request(struct vsc_tp *tp)
 {
@@ -383,6 +404,37 @@ int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb,
 }
 EXPORT_SYMBOL_NS_GPL(vsc_tp_register_event_cb, VSC_TP);
 
+/**
+ * vsc_tp_request_irq - request irq for vsc_tp device
+ * @tp: vsc_tp device handle
+ */
+int vsc_tp_request_irq(struct vsc_tp *tp)
+{
+       struct spi_device *spi = tp->spi;
+       struct device *dev = &spi->dev;
+       int ret;
+
+       irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);
+       ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                  dev_name(dev), tp);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_request_irq, VSC_TP);
+
+/**
+ * vsc_tp_free_irq - free irq for vsc_tp device
+ * @tp: vsc_tp device handle
+ */
+void vsc_tp_free_irq(struct vsc_tp *tp)
+{
+       free_irq(tp->spi->irq, tp);
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_free_irq, VSC_TP);
+
 /**
  * vsc_tp_intr_synchronize - synchronize vsc_tp interrupt
  * @tp: vsc_tp device handle
@@ -413,27 +465,6 @@ void vsc_tp_intr_disable(struct vsc_tp *tp)
 }
 EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_disable, VSC_TP);
 
-static irqreturn_t vsc_tp_isr(int irq, void *data)
-{
-       struct vsc_tp *tp = data;
-
-       atomic_inc(&tp->assert_cnt);
-
-       wake_up(&tp->xfer_wait);
-
-       return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
-{
-       struct vsc_tp *tp = data;
-
-       if (tp->event_notify)
-               tp->event_notify(tp->event_notify_context);
-
-       return IRQ_HANDLED;
-}
-
 static int vsc_tp_match_any(struct acpi_device *adev, void *data)
 {
        struct acpi_device **__adev = data;
@@ -490,10 +521,9 @@ static int vsc_tp_probe(struct spi_device *spi)
        tp->spi = spi;
 
        irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);
-       ret = devm_request_threaded_irq(dev, spi->irq, vsc_tp_isr,
-                                       vsc_tp_thread_isr,
-                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                       dev_name(dev), tp);
+       ret = request_threaded_irq(spi->irq, vsc_tp_isr, vsc_tp_thread_isr,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                  dev_name(dev), tp);
        if (ret)
                return ret;
 
@@ -522,6 +552,8 @@ static int vsc_tp_probe(struct spi_device *spi)
 err_destroy_lock:
        mutex_destroy(&tp->mutex);
 
+       free_irq(spi->irq, tp);
+
        return ret;
 }
 
@@ -532,6 +564,8 @@ static void vsc_tp_remove(struct spi_device *spi)
        platform_device_unregister(tp->pdev);
 
        mutex_destroy(&tp->mutex);
+
+       free_irq(spi->irq, tp);
 }
 
 static const struct acpi_device_id vsc_tp_acpi_ids[] = {
index f9513ddc3e409350ffe871af1ad30268226e6225..14ca195cbddccf23b15c03556411dbef95a18715 100644 (file)
@@ -37,6 +37,9 @@ int vsc_tp_xfer(struct vsc_tp *tp, u8 cmd, const void *obuf, size_t olen,
 int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb,
                             void *context);
 
+int vsc_tp_request_irq(struct vsc_tp *tp);
+void vsc_tp_free_irq(struct vsc_tp *tp);
+
 void vsc_tp_intr_enable(struct vsc_tp *tp);
 void vsc_tp_intr_disable(struct vsc_tp *tp);
 void vsc_tp_intr_synchronize(struct vsc_tp *tp);
This page took 0.062129 seconds and 4 git commands to generate.