From f6cbe27c1f5f14e826d2baaf10b659cc09d6aaf1 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Fri, 5 Feb 2021 10:54:19 +0530 Subject: [PATCH] rpmsg: glink: Use IRQF_NO_SUSPEND and pm_system_wakeup() for glink irq Glink irq should be wakeup capable, to achieve this irq is marked with enable_irq_wake(). There are some use cases where glink communication is required in system suspend path and glink interrupt handler needs to be run immediately. But wakeup cpabale interrupts even if received during suspend will not run immediately, this will be marked pending and run when system resumes from suspend. In such scenario there can be a potential deadock in suspend path due to any irq thread which is waiting for glink interrupt completion while glink interrupt cannot be handled immediately. One such use case is usb plugin interrupt received during suspend, which calls regulator api to communicate with rpm over glink and waits for rpm ack. RPM ack cannot be processed because glink interrupt received from rpm goes in pending state. Suspend path is blocked because regulator irq thread is still waiting. So there is requirement to run glink interrupt handler in suspend path at the same time making it wakeup capable. IRQ frameworks forbids usage of both IRQF_NO_SUSPEND and enable_irq_wake() together. This patch adds IRQF_NO_SUSPEND and pm_system_wakeup() for glink irq to implement this requirement. Change-Id: I1da199c9e10c640bb84d00e569c4fafc5c104d24 Signed-off-by: Deepak Kumar Singh --- drivers/rpmsg/qcom_glink_native.c | 28 ++++++++++++++++++++++++++++ drivers/rpmsg/qcom_glink_native.h | 1 + 2 files changed, 29 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 2c05863dfe9a..fb123c324b1c 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "rpmsg_internal.h" #include "qcom_glink_native.h" @@ -29,6 +30,8 @@ #define RPM_GLINK_CID_MIN 1 #define RPM_GLINK_CID_MAX 65536 +static int should_wake; + struct glink_msg { __le16 cmd; __le16 param1; @@ -1100,6 +1103,11 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data) unsigned int cmd; int ret = 0; + if (should_wake) { + pr_info("%s: wakeup %s\n", __func__, glink->irqname); + should_wake = false; + pm_system_wakeup(); + } /* To wakeup any blocking writers */ wake_up_all(&glink->tx_avail_notify); @@ -2017,5 +2025,25 @@ void qcom_glink_native_unregister(struct qcom_glink *glink) } EXPORT_SYMBOL_GPL(qcom_glink_native_unregister); +static int qcom_glink_suspend_no_irq(struct device *dev) +{ + should_wake = true; + + return 0; +} + +static int qcom_glink_resume_no_irq(struct device *dev) +{ + should_wake = false; + + return 0; +} + +const struct dev_pm_ops glink_native_pm_ops = { + .suspend_noirq = qcom_glink_suspend_no_irq, + .resume_noirq = qcom_glink_resume_no_irq, +}; +EXPORT_SYMBOL(glink_native_pm_ops); + MODULE_DESCRIPTION("Qualcomm GLINK driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h index b5feb6a9e4dd..a3be0f5cfaf4 100644 --- a/drivers/rpmsg/qcom_glink_native.h +++ b/drivers/rpmsg/qcom_glink_native.h @@ -27,6 +27,7 @@ struct qcom_glink_pipe { }; struct qcom_glink; +extern const struct dev_pm_ops glink_native_pm_ops; struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features,