root/drivers/remoteproc/qcom_common.c

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

DEFINITIONS

This source file includes following definitions.
  1. glink_subdev_start
  2. glink_subdev_stop
  3. qcom_add_glink_subdev
  4. qcom_remove_glink_subdev
  5. qcom_register_dump_segments
  6. smd_subdev_start
  7. smd_subdev_stop
  8. qcom_add_smd_subdev
  9. qcom_remove_smd_subdev
  10. qcom_register_ssr_notifier
  11. qcom_unregister_ssr_notifier
  12. ssr_notify_unprepare
  13. qcom_add_ssr_subdev
  14. qcom_remove_ssr_subdev

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Qualcomm Peripheral Image Loader helpers
   4  *
   5  * Copyright (C) 2016 Linaro Ltd
   6  * Copyright (C) 2015 Sony Mobile Communications Inc
   7  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
   8  */
   9 
  10 #include <linux/firmware.h>
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/notifier.h>
  14 #include <linux/remoteproc.h>
  15 #include <linux/rpmsg/qcom_glink.h>
  16 #include <linux/rpmsg/qcom_smd.h>
  17 #include <linux/soc/qcom/mdt_loader.h>
  18 
  19 #include "remoteproc_internal.h"
  20 #include "qcom_common.h"
  21 
  22 #define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev)
  23 #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev)
  24 #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev)
  25 
  26 static BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
  27 
  28 static int glink_subdev_start(struct rproc_subdev *subdev)
  29 {
  30         struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
  31 
  32         glink->edge = qcom_glink_smem_register(glink->dev, glink->node);
  33 
  34         return PTR_ERR_OR_ZERO(glink->edge);
  35 }
  36 
  37 static void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed)
  38 {
  39         struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
  40 
  41         qcom_glink_smem_unregister(glink->edge);
  42         glink->edge = NULL;
  43 }
  44 
  45 /**
  46  * qcom_add_glink_subdev() - try to add a GLINK subdevice to rproc
  47  * @rproc:      rproc handle to parent the subdevice
  48  * @glink:      reference to a GLINK subdev context
  49  */
  50 void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
  51 {
  52         struct device *dev = &rproc->dev;
  53 
  54         glink->node = of_get_child_by_name(dev->parent->of_node, "glink-edge");
  55         if (!glink->node)
  56                 return;
  57 
  58         glink->dev = dev;
  59         glink->subdev.start = glink_subdev_start;
  60         glink->subdev.stop = glink_subdev_stop;
  61 
  62         rproc_add_subdev(rproc, &glink->subdev);
  63 }
  64 EXPORT_SYMBOL_GPL(qcom_add_glink_subdev);
  65 
  66 /**
  67  * qcom_remove_glink_subdev() - remove a GLINK subdevice from rproc
  68  * @rproc:      rproc handle
  69  * @glink:      reference to a GLINK subdev context
  70  */
  71 void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
  72 {
  73         if (!glink->node)
  74                 return;
  75 
  76         rproc_remove_subdev(rproc, &glink->subdev);
  77         of_node_put(glink->node);
  78 }
  79 EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev);
  80 
  81 /**
  82  * qcom_register_dump_segments() - register segments for coredump
  83  * @rproc:      remoteproc handle
  84  * @fw:         firmware header
  85  *
  86  * Register all segments of the ELF in the remoteproc coredump segment list
  87  *
  88  * Return: 0 on success, negative errno on failure.
  89  */
  90 int qcom_register_dump_segments(struct rproc *rproc,
  91                                 const struct firmware *fw)
  92 {
  93         const struct elf32_phdr *phdrs;
  94         const struct elf32_phdr *phdr;
  95         const struct elf32_hdr *ehdr;
  96         int ret;
  97         int i;
  98 
  99         ehdr = (struct elf32_hdr *)fw->data;
 100         phdrs = (struct elf32_phdr *)(ehdr + 1);
 101 
 102         for (i = 0; i < ehdr->e_phnum; i++) {
 103                 phdr = &phdrs[i];
 104 
 105                 if (phdr->p_type != PT_LOAD)
 106                         continue;
 107 
 108                 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
 109                         continue;
 110 
 111                 if (!phdr->p_memsz)
 112                         continue;
 113 
 114                 ret = rproc_coredump_add_segment(rproc, phdr->p_paddr,
 115                                                  phdr->p_memsz);
 116                 if (ret)
 117                         return ret;
 118         }
 119 
 120         return 0;
 121 }
 122 EXPORT_SYMBOL_GPL(qcom_register_dump_segments);
 123 
 124 static int smd_subdev_start(struct rproc_subdev *subdev)
 125 {
 126         struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
 127 
 128         smd->edge = qcom_smd_register_edge(smd->dev, smd->node);
 129 
 130         return PTR_ERR_OR_ZERO(smd->edge);
 131 }
 132 
 133 static void smd_subdev_stop(struct rproc_subdev *subdev, bool crashed)
 134 {
 135         struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
 136 
 137         qcom_smd_unregister_edge(smd->edge);
 138         smd->edge = NULL;
 139 }
 140 
 141 /**
 142  * qcom_add_smd_subdev() - try to add a SMD subdevice to rproc
 143  * @rproc:      rproc handle to parent the subdevice
 144  * @smd:        reference to a Qualcomm subdev context
 145  */
 146 void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
 147 {
 148         struct device *dev = &rproc->dev;
 149 
 150         smd->node = of_get_child_by_name(dev->parent->of_node, "smd-edge");
 151         if (!smd->node)
 152                 return;
 153 
 154         smd->dev = dev;
 155         smd->subdev.start = smd_subdev_start;
 156         smd->subdev.stop = smd_subdev_stop;
 157 
 158         rproc_add_subdev(rproc, &smd->subdev);
 159 }
 160 EXPORT_SYMBOL_GPL(qcom_add_smd_subdev);
 161 
 162 /**
 163  * qcom_remove_smd_subdev() - remove the smd subdevice from rproc
 164  * @rproc:      rproc handle
 165  * @smd:        the SMD subdevice to remove
 166  */
 167 void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
 168 {
 169         if (!smd->node)
 170                 return;
 171 
 172         rproc_remove_subdev(rproc, &smd->subdev);
 173         of_node_put(smd->node);
 174 }
 175 EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev);
 176 
 177 /**
 178  * qcom_register_ssr_notifier() - register SSR notification handler
 179  * @nb:         notifier_block to notify for restart notifications
 180  *
 181  * Returns 0 on success, negative errno on failure.
 182  *
 183  * This register the @notify function as handler for restart notifications. As
 184  * remote processors are stopped this function will be called, with the SSR
 185  * name passed as a parameter.
 186  */
 187 int qcom_register_ssr_notifier(struct notifier_block *nb)
 188 {
 189         return blocking_notifier_chain_register(&ssr_notifiers, nb);
 190 }
 191 EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier);
 192 
 193 /**
 194  * qcom_unregister_ssr_notifier() - unregister SSR notification handler
 195  * @nb:         notifier_block to unregister
 196  */
 197 void qcom_unregister_ssr_notifier(struct notifier_block *nb)
 198 {
 199         blocking_notifier_chain_unregister(&ssr_notifiers, nb);
 200 }
 201 EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier);
 202 
 203 static void ssr_notify_unprepare(struct rproc_subdev *subdev)
 204 {
 205         struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
 206 
 207         blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr->name);
 208 }
 209 
 210 /**
 211  * qcom_add_ssr_subdev() - register subdevice as restart notification source
 212  * @rproc:      rproc handle
 213  * @ssr:        SSR subdevice handle
 214  * @ssr_name:   identifier to use for notifications originating from @rproc
 215  *
 216  * As the @ssr is registered with the @rproc SSR events will be sent to all
 217  * registered listeners in the system as the remoteproc is shut down.
 218  */
 219 void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
 220                          const char *ssr_name)
 221 {
 222         ssr->name = ssr_name;
 223         ssr->subdev.unprepare = ssr_notify_unprepare;
 224 
 225         rproc_add_subdev(rproc, &ssr->subdev);
 226 }
 227 EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev);
 228 
 229 /**
 230  * qcom_remove_ssr_subdev() - remove subdevice as restart notification source
 231  * @rproc:      rproc handle
 232  * @ssr:        SSR subdevice handle
 233  */
 234 void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr)
 235 {
 236         rproc_remove_subdev(rproc, &ssr->subdev);
 237 }
 238 EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev);
 239 
 240 MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver");
 241 MODULE_LICENSE("GPL v2");

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