root/drivers/soc/qcom/glink_ssr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qcom_glink_ssr_callback
  2. qcom_glink_ssr_notify
  3. qcom_glink_ssr_probe
  4. qcom_glink_ssr_remove

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

/* [<][>][^][v][top][bottom][index][help] */