^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2017, Linaro Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/rpmsg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/remoteproc/qcom_rproc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * struct do_cleanup_msg - The data structure for an SSR do_cleanup message
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * version: The G-Link SSR protocol version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * command: The G-Link SSR command - do_cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * seq_num: Sequence number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * name_len: Length of the name of the subsystem being restarted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * name: G-Link edge name of the subsystem being restarted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct do_cleanup_msg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) __le32 version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) __le32 command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) __le32 seq_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) __le32 name_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) char name[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * struct cleanup_done_msg - The data structure for an SSR cleanup_done message
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * version: The G-Link SSR protocol version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * response: The G-Link SSR response to a do_cleanup command, cleanup_done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * seq_num: Sequence number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct cleanup_done_msg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) __le32 version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) __le32 response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) __le32 seq_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * G-Link SSR protocol commands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define GLINK_SSR_DO_CLEANUP 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define GLINK_SSR_CLEANUP_DONE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct glink_ssr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct rpmsg_endpoint *ept;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct notifier_block nb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u32 seq_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct completion completion;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Notifier list for all registered glink_ssr instances */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * qcom_glink_ssr_notify() - notify GLINK SSR about stopped remoteproc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * @ssr_name: name of the remoteproc that has been stopped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void qcom_glink_ssr_notify(const char *ssr_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) EXPORT_SYMBOL_GPL(qcom_glink_ssr_notify);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) void *data, int len, void *priv, u32 addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct cleanup_done_msg *msg = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (len < sizeof(*msg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) dev_err(ssr->dev, "message too short\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (le32_to_cpu(msg->version) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (le32_to_cpu(msg->response) != GLINK_SSR_CLEANUP_DONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (le32_to_cpu(msg->seq_num) != ssr->seq_num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) dev_err(ssr->dev, "invalid sequence number of response\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) complete(&ssr->completion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static int qcom_glink_ssr_notifier_call(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) unsigned long event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct do_cleanup_msg msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) char *ssr_name = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ssr->seq_num++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) reinit_completion(&ssr->completion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) memset(&msg, 0, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) msg.seq_num = cpu_to_le32(ssr->seq_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) msg.name_len = cpu_to_le32(strlen(ssr_name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) strlcpy(msg.name, ssr_name, sizeof(msg.name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ret = rpmsg_send(ssr->ept, &msg, sizeof(msg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) dev_err(ssr->dev, "failed to send cleanup message\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ret = wait_for_completion_timeout(&ssr->completion, HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_err(ssr->dev, "timeout waiting for cleanup done message\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) static int qcom_glink_ssr_probe(struct rpmsg_device *rpdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct glink_ssr *ssr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ssr = devm_kzalloc(&rpdev->dev, sizeof(*ssr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (!ssr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) init_completion(&ssr->completion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ssr->dev = &rpdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ssr->ept = rpdev->ept;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ssr->nb.notifier_call = qcom_glink_ssr_notifier_call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) dev_set_drvdata(&rpdev->dev, ssr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return blocking_notifier_chain_register(&ssr_notifiers, &ssr->nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static void qcom_glink_ssr_remove(struct rpmsg_device *rpdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) blocking_notifier_chain_unregister(&ssr_notifiers, &ssr->nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static const struct rpmsg_device_id qcom_glink_ssr_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) { "glink_ssr" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static struct rpmsg_driver qcom_glink_ssr_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .probe = qcom_glink_ssr_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .remove = qcom_glink_ssr_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .callback = qcom_glink_ssr_callback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .id_table = qcom_glink_ssr_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .name = "qcom_glink_ssr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) module_rpmsg_driver(qcom_glink_ssr_driver);