Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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)  * Qualcomm Peripheral Image Loader helpers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2016 Linaro Ltd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Copyright (C) 2015 Sony Mobile Communications Inc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/remoteproc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/remoteproc/qcom_rproc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/rpmsg/qcom_glink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/rpmsg/qcom_smd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/soc/qcom/mdt_loader.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include "remoteproc_internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include "qcom_common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) struct qcom_ssr_subsystem {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	struct srcu_notifier_head notifier_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) static LIST_HEAD(qcom_ssr_subsystem_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) static DEFINE_MUTEX(qcom_ssr_subsys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static int glink_subdev_start(struct rproc_subdev *subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	glink->edge = qcom_glink_smem_register(glink->dev, glink->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	return PTR_ERR_OR_ZERO(glink->edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) static void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	qcom_glink_smem_unregister(glink->edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	glink->edge = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) static void glink_subdev_unprepare(struct rproc_subdev *subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	qcom_glink_ssr_notify(glink->ssr_name);
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62)  * qcom_add_glink_subdev() - try to add a GLINK subdevice to rproc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63)  * @rproc:	rproc handle to parent the subdevice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64)  * @glink:	reference to a GLINK subdev context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65)  * @ssr_name:	identifier of the associated remoteproc for ssr notifications
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 			   const char *ssr_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	struct device *dev = &rproc->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	glink->node = of_get_child_by_name(dev->parent->of_node, "glink-edge");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	if (!glink->node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	glink->ssr_name = kstrdup_const(ssr_name, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	if (!glink->ssr_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	glink->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	glink->subdev.start = glink_subdev_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	glink->subdev.stop = glink_subdev_stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	glink->subdev.unprepare = glink_subdev_unprepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	rproc_add_subdev(rproc, &glink->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) EXPORT_SYMBOL_GPL(qcom_add_glink_subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90)  * qcom_remove_glink_subdev() - remove a GLINK subdevice from rproc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91)  * @rproc:	rproc handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)  * @glink:	reference to a GLINK subdev context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	if (!glink->node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	rproc_remove_subdev(rproc, &glink->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	kfree_const(glink->ssr_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	of_node_put(glink->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)  * qcom_register_dump_segments() - register segments for coredump
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)  * @rproc:	remoteproc handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)  * @fw:		firmware header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)  * Register all segments of the ELF in the remoteproc coredump segment list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)  * Return: 0 on success, negative errno on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int qcom_register_dump_segments(struct rproc *rproc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 				const struct firmware *fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	const struct elf32_phdr *phdrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	const struct elf32_phdr *phdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	const struct elf32_hdr *ehdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	ehdr = (struct elf32_hdr *)fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	phdrs = (struct elf32_phdr *)(ehdr + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	for (i = 0; i < ehdr->e_phnum; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		phdr = &phdrs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		if (phdr->p_type != PT_LOAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		if (!phdr->p_memsz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		ret = rproc_coredump_add_segment(rproc, phdr->p_paddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 						 phdr->p_memsz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) EXPORT_SYMBOL_GPL(qcom_register_dump_segments);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static int smd_subdev_start(struct rproc_subdev *subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	smd->edge = qcom_smd_register_edge(smd->dev, smd->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	return PTR_ERR_OR_ZERO(smd->edge);
^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 void smd_subdev_stop(struct rproc_subdev *subdev, bool crashed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	qcom_smd_unregister_edge(smd->edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	smd->edge = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^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)  * qcom_add_smd_subdev() - try to add a SMD subdevice to rproc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)  * @rproc:	rproc handle to parent the subdevice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)  * @smd:	reference to a Qualcomm subdev context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	struct device *dev = &rproc->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	smd->node = of_get_child_by_name(dev->parent->of_node, "smd-edge");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	if (!smd->node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	smd->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	smd->subdev.start = smd_subdev_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	smd->subdev.stop = smd_subdev_stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	rproc_add_subdev(rproc, &smd->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) EXPORT_SYMBOL_GPL(qcom_add_smd_subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)  * qcom_remove_smd_subdev() - remove the smd subdevice from rproc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)  * @rproc:	rproc handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)  * @smd:	the SMD subdevice to remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	if (!smd->node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	rproc_remove_subdev(rproc, &smd->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	of_node_put(smd->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	struct qcom_ssr_subsystem *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	mutex_lock(&qcom_ssr_subsys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	/* Match in the global qcom_ssr_subsystem_list with name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	list_for_each_entry(info, &qcom_ssr_subsystem_list, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		if (!strcmp(info->name, name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	info = kzalloc(sizeof(*info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		info = ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	info->name = kstrdup_const(name, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	srcu_init_notifier_head(&info->notifier_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	/* Add to global notification list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	list_add_tail(&info->list, &qcom_ssr_subsystem_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	mutex_unlock(&qcom_ssr_subsys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	return info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)  * qcom_register_ssr_notifier() - register SSR notification handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)  * @name:	Subsystem's SSR name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)  * @nb:		notifier_block to be invoked upon subsystem's state change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)  * This registers the @nb notifier block as part the notifier chain for a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)  * remoteproc associated with @name. The notifier block's callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)  * will be invoked when the remote processor's SSR events occur
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)  * (pre/post startup and pre/post shutdown).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)  * Return: a subsystem cookie on success, ERR_PTR on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	struct qcom_ssr_subsystem *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	info = qcom_ssr_get_subsys(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	if (IS_ERR(info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		return info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	srcu_notifier_chain_register(&info->notifier_list, nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	return &info->notifier_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)  * qcom_unregister_ssr_notifier() - unregister SSR notification handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)  * @notify:	subsystem cookie returned from qcom_register_ssr_notifier
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)  * @nb:		notifier_block to unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)  * This function will unregister the notifier from the particular notifier
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)  * chain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)  * Return: 0 on success, %ENOENT otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	return srcu_notifier_chain_unregister(notify, nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static int ssr_notify_prepare(struct rproc_subdev *subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	struct qcom_ssr_notify_data data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 		.name = ssr->info->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		.crashed = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	srcu_notifier_call_chain(&ssr->info->notifier_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 				 QCOM_SSR_BEFORE_POWERUP, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static int ssr_notify_start(struct rproc_subdev *subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	struct qcom_ssr_notify_data data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		.name = ssr->info->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		.crashed = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	srcu_notifier_call_chain(&ssr->info->notifier_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 				 QCOM_SSR_AFTER_POWERUP, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	struct qcom_ssr_notify_data data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 		.name = ssr->info->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 		.crashed = crashed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	srcu_notifier_call_chain(&ssr->info->notifier_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 				 QCOM_SSR_BEFORE_SHUTDOWN, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static void ssr_notify_unprepare(struct rproc_subdev *subdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	struct qcom_ssr_notify_data data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		.name = ssr->info->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 		.crashed = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	srcu_notifier_call_chain(&ssr->info->notifier_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 				 QCOM_SSR_AFTER_SHUTDOWN, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)  * qcom_add_ssr_subdev() - register subdevice as restart notification source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)  * @rproc:	rproc handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)  * @ssr:	SSR subdevice handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)  * @ssr_name:	identifier to use for notifications originating from @rproc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)  * As the @ssr is registered with the @rproc SSR events will be sent to all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)  * registered listeners for the remoteproc when it's SSR events occur
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)  * (pre/post startup and pre/post shutdown).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 			 const char *ssr_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	struct qcom_ssr_subsystem *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	info = qcom_ssr_get_subsys(ssr_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	if (IS_ERR(info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 		dev_err(&rproc->dev, "Failed to add ssr subdevice\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	ssr->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	ssr->subdev.prepare = ssr_notify_prepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	ssr->subdev.start = ssr_notify_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	ssr->subdev.stop = ssr_notify_stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	ssr->subdev.unprepare = ssr_notify_unprepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	rproc_add_subdev(rproc, &ssr->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)  * qcom_remove_ssr_subdev() - remove subdevice as restart notification source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)  * @rproc:	rproc handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)  * @ssr:	SSR subdevice handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	rproc_remove_subdev(rproc, &ssr->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	ssr->info = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) MODULE_LICENSE("GPL v2");