Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
0004  * Copyright (c) 2017, Linaro Ltd.
0005  */
0006 
0007 #include <linux/completion.h>
0008 #include <linux/module.h>
0009 #include <linux/notifier.h>
0010 #include <linux/rpmsg.h>
0011 #include <linux/rpmsg/qcom_glink.h>
0012 #include <linux/remoteproc/qcom_rproc.h>
0013 
0014 /**
0015  * struct do_cleanup_msg - The data structure for an SSR do_cleanup message
0016  * @version:    The G-Link SSR protocol version
0017  * @command:    The G-Link SSR command - do_cleanup
0018  * @seq_num:    Sequence number
0019  * @name_len:   Length of the name of the subsystem being restarted
0020  * @name:   G-Link edge name of the subsystem being restarted
0021  */
0022 struct do_cleanup_msg {
0023     __le32 version;
0024     __le32 command;
0025     __le32 seq_num;
0026     __le32 name_len;
0027     char name[32];
0028 };
0029 
0030 /**
0031  * struct cleanup_done_msg - The data structure for an SSR cleanup_done message
0032  * @version:    The G-Link SSR protocol version
0033  * @response:   The G-Link SSR response to a do_cleanup command, cleanup_done
0034  * @seq_num:    Sequence number
0035  */
0036 struct cleanup_done_msg {
0037     __le32 version;
0038     __le32 response;
0039     __le32 seq_num;
0040 };
0041 
0042 /*
0043  * G-Link SSR protocol commands
0044  */
0045 #define GLINK_SSR_DO_CLEANUP    0
0046 #define GLINK_SSR_CLEANUP_DONE  1
0047 
0048 struct glink_ssr {
0049     struct device *dev;
0050     struct rpmsg_endpoint *ept;
0051 
0052     struct notifier_block nb;
0053 
0054     u32 seq_num;
0055     struct completion completion;
0056 };
0057 
0058 /* Notifier list for all registered glink_ssr instances */
0059 static BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
0060 
0061 /**
0062  * qcom_glink_ssr_notify() - notify GLINK SSR about stopped remoteproc
0063  * @ssr_name:   name of the remoteproc that has been stopped
0064  */
0065 void qcom_glink_ssr_notify(const char *ssr_name)
0066 {
0067     blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr_name);
0068 }
0069 EXPORT_SYMBOL_GPL(qcom_glink_ssr_notify);
0070 
0071 static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev,
0072                    void *data, int len, void *priv, u32 addr)
0073 {
0074     struct cleanup_done_msg *msg = data;
0075     struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev);
0076 
0077     if (len < sizeof(*msg)) {
0078         dev_err(ssr->dev, "message too short\n");
0079         return -EINVAL;
0080     }
0081 
0082     if (le32_to_cpu(msg->version) != 0)
0083         return -EINVAL;
0084 
0085     if (le32_to_cpu(msg->response) != GLINK_SSR_CLEANUP_DONE)
0086         return 0;
0087 
0088     if (le32_to_cpu(msg->seq_num) != ssr->seq_num) {
0089         dev_err(ssr->dev, "invalid sequence number of response\n");
0090         return -EINVAL;
0091     }
0092 
0093     complete(&ssr->completion);
0094 
0095     return 0;
0096 }
0097 
0098 static int qcom_glink_ssr_notifier_call(struct notifier_block *nb,
0099                     unsigned long event,
0100                     void *data)
0101 {
0102     struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb);
0103     struct do_cleanup_msg msg;
0104     char *ssr_name = data;
0105     int ret;
0106 
0107     ssr->seq_num++;
0108     reinit_completion(&ssr->completion);
0109 
0110     memset(&msg, 0, sizeof(msg));
0111     msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP);
0112     msg.seq_num = cpu_to_le32(ssr->seq_num);
0113     msg.name_len = cpu_to_le32(strlen(ssr_name));
0114     strlcpy(msg.name, ssr_name, sizeof(msg.name));
0115 
0116     ret = rpmsg_send(ssr->ept, &msg, sizeof(msg));
0117     if (ret < 0)
0118         dev_err(ssr->dev, "failed to send cleanup message\n");
0119 
0120     ret = wait_for_completion_timeout(&ssr->completion, HZ);
0121     if (!ret)
0122         dev_err(ssr->dev, "timeout waiting for cleanup done message\n");
0123 
0124     return NOTIFY_DONE;
0125 }
0126 
0127 static int qcom_glink_ssr_probe(struct rpmsg_device *rpdev)
0128 {
0129     struct glink_ssr *ssr;
0130 
0131     ssr = devm_kzalloc(&rpdev->dev, sizeof(*ssr), GFP_KERNEL);
0132     if (!ssr)
0133         return -ENOMEM;
0134 
0135     init_completion(&ssr->completion);
0136 
0137     ssr->dev = &rpdev->dev;
0138     ssr->ept = rpdev->ept;
0139     ssr->nb.notifier_call = qcom_glink_ssr_notifier_call;
0140 
0141     dev_set_drvdata(&rpdev->dev, ssr);
0142 
0143     return blocking_notifier_chain_register(&ssr_notifiers, &ssr->nb);
0144 }
0145 
0146 static void qcom_glink_ssr_remove(struct rpmsg_device *rpdev)
0147 {
0148     struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev);
0149 
0150     blocking_notifier_chain_unregister(&ssr_notifiers, &ssr->nb);
0151 }
0152 
0153 static const struct rpmsg_device_id qcom_glink_ssr_match[] = {
0154     { "glink_ssr" },
0155     {}
0156 };
0157 
0158 static struct rpmsg_driver qcom_glink_ssr_driver = {
0159     .probe = qcom_glink_ssr_probe,
0160     .remove = qcom_glink_ssr_remove,
0161     .callback = qcom_glink_ssr_callback,
0162     .id_table = qcom_glink_ssr_match,
0163     .drv = {
0164         .name = "qcom_glink_ssr",
0165     },
0166 };
0167 module_rpmsg_driver(qcom_glink_ssr_driver);