Like qcom_sysmon's SSCTL notify, clustered remote processors (e.g. Nord's HPASS ADSP0/1/2) cannot handle the glink_ssr DO_CLEANUP broadcast sent to siblings whenever one of them starts or stops, leaving qcom_glink_ssr_notifier_call() to time out waiting for CLEANUP_DONE.
Pass the stopping remoteproc's cluster identifier through qcom_glink_ssr_notify(), and plumb each edge's own cluster identifier down from the remoteproc that registers it, so that qcom_glink_ssr_notifier_call() can skip the DO_CLEANUP send when the sender and the receiving edge share a cluster. As in qcom_sysmon, the suppression is done on the receiving side, so that a cluster member keeps sending DO_CLEANUP to, and receiving it from, remote processors outside its cluster. Edges with no cluster set are unaffected. The receiving edge's identifier is carried in struct qcom_glink rather than looked up from the rproc that owns it, so that glink_ssr does not have to reach into struct remoteproc: RPMSG_QCOM_GLINK does not depend on REMOTEPROC, and the identifier is deliberately opaque to keep the two subsystems independent of each other. Assisted-by: LLM Signed-off-by: Shawn Guo <[email protected]> --- drivers/remoteproc/qcom_common.c | 7 +++--- drivers/remoteproc/qcom_common.h | 2 +- drivers/rpmsg/qcom_glink_native.c | 20 ++++++++++++++++- drivers/rpmsg/qcom_glink_native.h | 5 ++++- drivers/rpmsg/qcom_glink_rpm.c | 2 +- drivers/rpmsg/qcom_glink_smem.c | 5 +++-- drivers/rpmsg/qcom_glink_ssr.c | 36 ++++++++++++++++++++++++++----- include/linux/rpmsg/qcom_glink.h | 10 +++++---- 8 files changed, 69 insertions(+), 18 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 5294e327f158..13458bda6b24 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -217,7 +217,8 @@ static int glink_subdev_start(struct rproc_subdev *subdev) { struct qcom_rproc_glink *glink = to_glink_subdev(subdev); - glink->edge = qcom_glink_smem_register(glink->dev, glink->node); + glink->edge = qcom_glink_smem_register(&glink->rproc->dev, glink->node, + glink->rproc->cluster); return PTR_ERR_OR_ZERO(glink->edge); } @@ -234,7 +235,7 @@ static void glink_subdev_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_glink *glink = to_glink_subdev(subdev); - qcom_glink_ssr_notify(glink->ssr_name); + qcom_glink_ssr_notify(glink->ssr_name, glink->rproc->cluster); } /** @@ -258,7 +259,7 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink, return; } - glink->dev = dev; + glink->rproc = rproc; glink->subdev.start = glink_subdev_start; glink->subdev.stop = glink_subdev_stop; glink->subdev.unprepare = glink_subdev_unprepare; diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h index b0e7e336d363..7136494cbfba 100644 --- a/drivers/remoteproc/qcom_common.h +++ b/drivers/remoteproc/qcom_common.h @@ -14,7 +14,7 @@ struct qcom_rproc_glink { const char *ssr_name; - struct device *dev; + struct rproc *rproc; struct device_node *node; struct qcom_glink_smem *edge; }; diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 55793fc18293..06494f4d3a4f 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -122,6 +122,8 @@ struct qcom_glink { unsigned long features; bool intentless; + /* Cluster identifier of the remote processor behind this edge, or NULL */ + void *cluster; wait_queue_head_t tx_avail_notify; bool sent_read_notify; @@ -1889,7 +1891,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, struct qcom_glink_pipe *tx, - bool intentless) + bool intentless, + void *cluster) { int ret; struct qcom_glink *glink; @@ -1904,6 +1907,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, glink->features = features; glink->intentless = intentless; + glink->cluster = cluster; spin_lock_init(&glink->tx_lock); spin_lock_init(&glink->rx_lock); @@ -1937,6 +1941,20 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, } EXPORT_SYMBOL_GPL(qcom_glink_native_probe); +/** + * qcom_glink_ept_cluster() - cluster identifier of an endpoint's edge + * @ept: endpoint to query + * + * Return: the opaque cluster identifier of the remote processor @ept talks to, + * or NULL if it is not part of a cluster. + */ +void *qcom_glink_ept_cluster(struct rpmsg_endpoint *ept) +{ + struct glink_channel *channel = to_glink_channel(ept); + + return channel->glink->cluster; +} + static int qcom_glink_remove_device(struct device *dev, void *data) { device_unregister(dev); diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h index 8dbec24de23e..8544f4f5c545 100644 --- a/drivers/rpmsg/qcom_glink_native.h +++ b/drivers/rpmsg/qcom_glink_native.h @@ -29,12 +29,15 @@ struct qcom_glink_pipe { struct device; struct qcom_glink; +struct rpmsg_endpoint; struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, struct qcom_glink_pipe *tx, - bool intentless); + bool intentless, + void *cluster); +void *qcom_glink_ept_cluster(struct rpmsg_endpoint *ept); void qcom_glink_native_remove(struct qcom_glink *glink); void qcom_glink_native_rx(struct qcom_glink *glink); diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c index e3ba2c63a5fc..9c1ff05d4a10 100644 --- a/drivers/rpmsg/qcom_glink_rpm.c +++ b/drivers/rpmsg/qcom_glink_rpm.c @@ -346,7 +346,7 @@ static int glink_rpm_probe(struct platform_device *pdev) 0, &rpm->rx_pipe.native, &rpm->tx_pipe.native, - true); + true, NULL); if (IS_ERR(glink)) { mbox_free_channel(rpm->mbox_chan); return PTR_ERR(glink); diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index 35bb03e67ae8..938f9575784e 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -225,7 +225,8 @@ static void qcom_glink_smem_release(struct device *dev) } struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent, - struct device_node *node) + struct device_node *node, + void *cluster) { struct glink_smem_pipe *rx_pipe; struct glink_smem_pipe *tx_pipe; @@ -345,7 +346,7 @@ struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent, glink = qcom_glink_native_probe(dev, GLINK_FEATURE_INTENT_REUSE, &rx_pipe->native, &tx_pipe->native, - false); + false, cluster); if (IS_ERR(glink)) { ret = PTR_ERR(glink); goto err_free_mbox; diff --git a/drivers/rpmsg/qcom_glink_ssr.c b/drivers/rpmsg/qcom_glink_ssr.c index e71d3716c55c..74c671a19af0 100644 --- a/drivers/rpmsg/qcom_glink_ssr.c +++ b/drivers/rpmsg/qcom_glink_ssr.c @@ -11,6 +11,8 @@ #include <linux/rpmsg/qcom_glink.h> #include <linux/remoteproc/qcom_rproc.h> +#include "qcom_glink_native.h" + /** * struct do_cleanup_msg - The data structure for an SSR do_cleanup message * @version: The G-Link SSR protocol version @@ -55,16 +57,34 @@ struct glink_ssr { struct completion completion; }; +/** + * struct glink_ssr_notify_data - payload of an SSR notification + * @ssr_name: name of the remoteproc that has been stopped + * @cluster: cluster identifier of the remoteproc that has been stopped, + * or NULL if it is not part of a cluster + */ +struct glink_ssr_notify_data { + const char *ssr_name; + void *cluster; +}; + /* Notifier list for all registered glink_ssr instances */ static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); /** * qcom_glink_ssr_notify() - notify GLINK SSR about stopped remoteproc * @ssr_name: name of the remoteproc that has been stopped + * @cluster: cluster identifier of the remoteproc that has been stopped, + * or NULL if it is not part of a cluster */ -void qcom_glink_ssr_notify(const char *ssr_name) +void qcom_glink_ssr_notify(const char *ssr_name, void *cluster) { - blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr_name); + struct glink_ssr_notify_data data = { + .ssr_name = ssr_name, + .cluster = cluster, + }; + + blocking_notifier_call_chain(&ssr_notifiers, 0, &data); } EXPORT_SYMBOL_GPL(qcom_glink_ssr_notify); @@ -100,18 +120,24 @@ static int qcom_glink_ssr_notifier_call(struct notifier_block *nb, void *data) { struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb); + struct glink_ssr_notify_data *notify_data = data; struct do_cleanup_msg msg; - char *ssr_name = data; + void *cluster; int ret; + /* Cluster siblings' firmware can't handle peer SSR notify; skip it */ + cluster = qcom_glink_ept_cluster(ssr->ept); + if (cluster && cluster == notify_data->cluster) + return NOTIFY_DONE; + ssr->seq_num++; reinit_completion(&ssr->completion); memset(&msg, 0, sizeof(msg)); msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP); msg.seq_num = cpu_to_le32(ssr->seq_num); - msg.name_len = cpu_to_le32(strlen(ssr_name)); - strscpy(msg.name, ssr_name, sizeof(msg.name)); + msg.name_len = cpu_to_le32(strlen(notify_data->ssr_name)); + strscpy(msg.name, notify_data->ssr_name, sizeof(msg.name)); ret = rpmsg_send(ssr->ept, &msg, sizeof(msg)); if (ret < 0) diff --git a/include/linux/rpmsg/qcom_glink.h b/include/linux/rpmsg/qcom_glink.h index bfbd48f435fa..6591d016e8cb 100644 --- a/include/linux/rpmsg/qcom_glink.h +++ b/include/linux/rpmsg/qcom_glink.h @@ -8,22 +8,24 @@ struct qcom_glink_smem; #if IS_ENABLED(CONFIG_RPMSG_QCOM_GLINK) -void qcom_glink_ssr_notify(const char *ssr_name); +void qcom_glink_ssr_notify(const char *ssr_name, void *cluster); #else -static inline void qcom_glink_ssr_notify(const char *ssr_name) {} +static inline void qcom_glink_ssr_notify(const char *ssr_name, void *cluster) {} #endif #if IS_ENABLED(CONFIG_RPMSG_QCOM_GLINK_SMEM) struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent, - struct device_node *node); + struct device_node *node, + void *cluster); void qcom_glink_smem_unregister(struct qcom_glink_smem *glink); #else static inline struct qcom_glink_smem * qcom_glink_smem_register(struct device *parent, - struct device_node *node) + struct device_node *node, + void *cluster) { return NULL; } -- 2.43.0

