From 1b8b9571dddf67c71c9218c4eb921a37a2f7154c Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 1 Aug 2022 22:48:22 -0700 Subject: [PATCH] rpmsg: glink: Add early reset notifier Currently when a remote subsystem goes down, remove_subdev will be called from rproc for removing that subsystem from the list, but this could be too late. Register for early SSR notifications for getting notified about before shutdown, so that the glink_send calls to the dead processor will not get blocked. Change-Id: Ief7f90caf69f2855272579bc63140837e0efc447 Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_native.c | 35 ++++++++++++++++++++++--------- include/linux/rpmsg/qcom_glink.h | 3 +++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 43afd29e82ee..7294902c4274 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1777,6 +1777,29 @@ static void qcom_glink_work(struct work_struct *work) } } +void qcom_glink_early_ssr_notify(void *data) +{ + struct qcom_glink *glink = data; + struct glink_channel *channel; + unsigned long flags; + int cid; + + if (!glink) + return; + atomic_inc(&glink->in_reset); + + /* To wakeup any blocking writers */ + wake_up_all(&glink->tx_avail_notify); + + spin_lock_irqsave(&glink->idr_lock, flags); + idr_for_each_entry(&glink->lcids, channel, cid) { + wake_up(&channel->intent_req_ack); + wake_up(&channel->intent_req_comp); + } + spin_unlock_irqrestore(&glink->idr_lock, flags); +} +EXPORT_SYMBOL(qcom_glink_early_ssr_notify); + static void qcom_glink_cancel_rx_work(struct qcom_glink *glink) { struct glink_defer_cmd *dcmd; @@ -1895,6 +1918,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, } scnprintf(glink->irqname, 32, "glink-native-%s", glink->name); + irq = of_irq_get(dev->of_node, 0); ret = devm_request_irq(dev, irq, qcom_glink_native_intr, @@ -1929,22 +1953,13 @@ static int qcom_glink_remove_device(struct device *dev, void *data) void qcom_glink_native_remove(struct qcom_glink *glink) { struct glink_channel *channel; - unsigned long flags; int cid; int ret; - atomic_inc(&glink->in_reset); + qcom_glink_early_ssr_notify(glink); disable_irq(glink->irq); qcom_glink_cancel_rx_work(glink); - /* Signal all threads to cancel tx */ - spin_lock_irqsave(&glink->idr_lock, flags); - idr_for_each_entry(&glink->lcids, channel, cid) { - wake_up(&channel->intent_req_ack); - wake_up(&channel->intent_req_comp); - } - spin_unlock_irqrestore(&glink->idr_lock, flags); - ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device); if (ret) dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); diff --git a/include/linux/rpmsg/qcom_glink.h b/include/linux/rpmsg/qcom_glink.h index 22fc3a69b683..a086256ec8ba 100644 --- a/include/linux/rpmsg/qcom_glink.h +++ b/include/linux/rpmsg/qcom_glink.h @@ -18,6 +18,7 @@ static inline void qcom_glink_ssr_notify(const char *ssr_name) {} struct qcom_glink *qcom_glink_smem_register(struct device *parent, struct device_node *node); void qcom_glink_smem_unregister(struct qcom_glink *glink); +void qcom_glink_early_ssr_notify(void *data); #else @@ -29,6 +30,8 @@ qcom_glink_smem_register(struct device *parent, } static inline void qcom_glink_smem_unregister(struct qcom_glink *glink) {} +static inline void qcom_glink_ssr_notify(const char *ssr_name) {} +static inline void qcom_glink_early_ssr_notify(void *data) {} #endif #endif