0001
0002
0003
0004
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
0016
0017
0018
0019
0020
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
0032
0033
0034
0035
0036 struct cleanup_done_msg {
0037 __le32 version;
0038 __le32 response;
0039 __le32 seq_num;
0040 };
0041
0042
0043
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
0059 static BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
0060
0061
0062
0063
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);