Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15-rc6 164 lines 4.2 kB view raw
1/* 2 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2017, Linaro Ltd. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 and 7 * only version 2 as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15#include <linux/completion.h> 16#include <linux/module.h> 17#include <linux/notifier.h> 18#include <linux/rpmsg.h> 19#include <linux/remoteproc/qcom_rproc.h> 20 21/** 22 * struct do_cleanup_msg - The data structure for an SSR do_cleanup message 23 * version: The G-Link SSR protocol version 24 * command: The G-Link SSR command - do_cleanup 25 * seq_num: Sequence number 26 * name_len: Length of the name of the subsystem being restarted 27 * name: G-Link edge name of the subsystem being restarted 28 */ 29struct do_cleanup_msg { 30 __le32 version; 31 __le32 command; 32 __le32 seq_num; 33 __le32 name_len; 34 char name[32]; 35}; 36 37/** 38 * struct cleanup_done_msg - The data structure for an SSR cleanup_done message 39 * version: The G-Link SSR protocol version 40 * response: The G-Link SSR response to a do_cleanup command, cleanup_done 41 * seq_num: Sequence number 42 */ 43struct cleanup_done_msg { 44 __le32 version; 45 __le32 response; 46 __le32 seq_num; 47}; 48 49/** 50 * G-Link SSR protocol commands 51 */ 52#define GLINK_SSR_DO_CLEANUP 0 53#define GLINK_SSR_CLEANUP_DONE 1 54 55struct glink_ssr { 56 struct device *dev; 57 struct rpmsg_endpoint *ept; 58 59 struct notifier_block nb; 60 61 u32 seq_num; 62 struct completion completion; 63}; 64 65static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev, 66 void *data, int len, void *priv, u32 addr) 67{ 68 struct cleanup_done_msg *msg = data; 69 struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); 70 71 if (len < sizeof(*msg)) { 72 dev_err(ssr->dev, "message too short\n"); 73 return -EINVAL; 74 } 75 76 if (le32_to_cpu(msg->version) != 0) 77 return -EINVAL; 78 79 if (le32_to_cpu(msg->response) != GLINK_SSR_CLEANUP_DONE) 80 return 0; 81 82 if (le32_to_cpu(msg->seq_num) != ssr->seq_num) { 83 dev_err(ssr->dev, "invalid sequence number of response\n"); 84 return -EINVAL; 85 } 86 87 complete(&ssr->completion); 88 89 return 0; 90} 91 92static int qcom_glink_ssr_notify(struct notifier_block *nb, unsigned long event, 93 void *data) 94{ 95 struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb); 96 struct do_cleanup_msg msg; 97 char *ssr_name = data; 98 int ret; 99 100 ssr->seq_num++; 101 reinit_completion(&ssr->completion); 102 103 memset(&msg, 0, sizeof(msg)); 104 msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP); 105 msg.seq_num = cpu_to_le32(ssr->seq_num); 106 msg.name_len = cpu_to_le32(strlen(ssr_name)); 107 strlcpy(msg.name, ssr_name, sizeof(msg.name)); 108 109 ret = rpmsg_send(ssr->ept, &msg, sizeof(msg)); 110 if (ret < 0) 111 dev_err(ssr->dev, "failed to send cleanup message\n"); 112 113 ret = wait_for_completion_timeout(&ssr->completion, HZ); 114 if (!ret) 115 dev_err(ssr->dev, "timeout waiting for cleanup done message\n"); 116 117 return NOTIFY_DONE; 118} 119 120static int qcom_glink_ssr_probe(struct rpmsg_device *rpdev) 121{ 122 struct glink_ssr *ssr; 123 124 ssr = devm_kzalloc(&rpdev->dev, sizeof(*ssr), GFP_KERNEL); 125 if (!ssr) 126 return -ENOMEM; 127 128 init_completion(&ssr->completion); 129 130 ssr->dev = &rpdev->dev; 131 ssr->ept = rpdev->ept; 132 ssr->nb.notifier_call = qcom_glink_ssr_notify; 133 134 dev_set_drvdata(&rpdev->dev, ssr); 135 136 return qcom_register_ssr_notifier(&ssr->nb); 137} 138 139static void qcom_glink_ssr_remove(struct rpmsg_device *rpdev) 140{ 141 struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); 142 143 qcom_unregister_ssr_notifier(&ssr->nb); 144} 145 146static const struct rpmsg_device_id qcom_glink_ssr_match[] = { 147 { "glink_ssr" }, 148 {} 149}; 150 151static struct rpmsg_driver qcom_glink_ssr_driver = { 152 .probe = qcom_glink_ssr_probe, 153 .remove = qcom_glink_ssr_remove, 154 .callback = qcom_glink_ssr_callback, 155 .id_table = qcom_glink_ssr_match, 156 .drv = { 157 .name = "qcom_glink_ssr", 158 }, 159}; 160module_rpmsg_driver(qcom_glink_ssr_driver); 161 162MODULE_ALIAS("rpmsg:glink_ssr"); 163MODULE_DESCRIPTION("Qualcomm GLINK SSR notifier"); 164MODULE_LICENSE("GPL v2");