remoteproc: qcom: Add support for SSR notifications
This adds the remoteproc part of subsystem restart, which is responsible for emitting notifications to other processors in the system about a dying remoteproc instance. These notifications are propagated to the various communication systems in the various remote processors to shut down communication links that was left in a dangling state as the remoteproc was stopped (or crashed). Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
This commit is contained in:
Родитель
1b0ef9068f
Коммит
1e140df049
|
@ -38,6 +38,7 @@ struct adsp_data {
|
||||||
const char *firmware_name;
|
const char *firmware_name;
|
||||||
int pas_id;
|
int pas_id;
|
||||||
bool has_aggre2_clk;
|
bool has_aggre2_clk;
|
||||||
|
const char *ssr_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qcom_adsp {
|
struct qcom_adsp {
|
||||||
|
@ -72,6 +73,7 @@ struct qcom_adsp {
|
||||||
size_t mem_size;
|
size_t mem_size;
|
||||||
|
|
||||||
struct qcom_rproc_subdev smd_subdev;
|
struct qcom_rproc_subdev smd_subdev;
|
||||||
|
struct qcom_rproc_ssr ssr_subdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
|
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
|
||||||
|
@ -402,6 +404,7 @@ static int adsp_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
|
qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
|
||||||
|
qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
|
||||||
|
|
||||||
ret = rproc_add(rproc);
|
ret = rproc_add(rproc);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -423,6 +426,7 @@ static int adsp_remove(struct platform_device *pdev)
|
||||||
rproc_del(adsp->rproc);
|
rproc_del(adsp->rproc);
|
||||||
|
|
||||||
qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
|
qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
|
||||||
|
qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
|
||||||
rproc_free(adsp->rproc);
|
rproc_free(adsp->rproc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -433,6 +437,7 @@ static const struct adsp_data adsp_resource_init = {
|
||||||
.firmware_name = "adsp.mdt",
|
.firmware_name = "adsp.mdt",
|
||||||
.pas_id = 1,
|
.pas_id = 1,
|
||||||
.has_aggre2_clk = false,
|
.has_aggre2_clk = false,
|
||||||
|
.ssr_name = "lpass",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct adsp_data slpi_resource_init = {
|
static const struct adsp_data slpi_resource_init = {
|
||||||
|
@ -440,6 +445,7 @@ static const struct adsp_data slpi_resource_init = {
|
||||||
.firmware_name = "slpi.mdt",
|
.firmware_name = "slpi.mdt",
|
||||||
.pas_id = 12,
|
.pas_id = 12,
|
||||||
.has_aggre2_clk = true,
|
.has_aggre2_clk = true,
|
||||||
|
.ssr_name = "dsps",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id adsp_of_match[] = {
|
static const struct of_device_id adsp_of_match[] = {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
#include <linux/remoteproc.h>
|
#include <linux/remoteproc.h>
|
||||||
#include <linux/rpmsg/qcom_smd.h>
|
#include <linux/rpmsg/qcom_smd.h>
|
||||||
|
|
||||||
|
@ -25,6 +26,9 @@
|
||||||
#include "qcom_common.h"
|
#include "qcom_common.h"
|
||||||
|
|
||||||
#define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev)
|
#define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev)
|
||||||
|
#define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev)
|
||||||
|
|
||||||
|
BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc
|
* qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc
|
||||||
|
@ -92,5 +96,72 @@ void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev);
|
EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcom_register_ssr_notifier() - register SSR notification handler
|
||||||
|
* @nb: notifier_block to notify for restart notifications
|
||||||
|
*
|
||||||
|
* Returns 0 on success, negative errno on failure.
|
||||||
|
*
|
||||||
|
* This register the @notify function as handler for restart notifications. As
|
||||||
|
* remote processors are stopped this function will be called, with the SSR
|
||||||
|
* name passed as a parameter.
|
||||||
|
*/
|
||||||
|
int qcom_register_ssr_notifier(struct notifier_block *nb)
|
||||||
|
{
|
||||||
|
return blocking_notifier_chain_register(&ssr_notifiers, nb);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcom_unregister_ssr_notifier() - unregister SSR notification handler
|
||||||
|
* @nb: notifier_block to unregister
|
||||||
|
*/
|
||||||
|
void qcom_unregister_ssr_notifier(struct notifier_block *nb)
|
||||||
|
{
|
||||||
|
blocking_notifier_chain_unregister(&ssr_notifiers, nb);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier);
|
||||||
|
|
||||||
|
static int ssr_notify_start(struct rproc_subdev *subdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ssr_notify_stop(struct rproc_subdev *subdev)
|
||||||
|
{
|
||||||
|
struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
|
||||||
|
|
||||||
|
blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcom_add_ssr_subdev() - register subdevice as restart notification source
|
||||||
|
* @rproc: rproc handle
|
||||||
|
* @ssr: SSR subdevice handle
|
||||||
|
* @ssr_name: identifier to use for notifications originating from @rproc
|
||||||
|
*
|
||||||
|
* As the @ssr is registered with the @rproc SSR events will be sent to all
|
||||||
|
* registered listeners in the system as the remoteproc is shut down.
|
||||||
|
*/
|
||||||
|
void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
|
||||||
|
const char *ssr_name)
|
||||||
|
{
|
||||||
|
ssr->name = ssr_name;
|
||||||
|
|
||||||
|
rproc_add_subdev(rproc, &ssr->subdev, ssr_notify_start, ssr_notify_stop);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcom_remove_ssr_subdev() - remove subdevice as restart notification source
|
||||||
|
* @rproc: rproc handle
|
||||||
|
* @ssr: SSR subdevice handle
|
||||||
|
*/
|
||||||
|
void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr)
|
||||||
|
{
|
||||||
|
rproc_remove_subdev(rproc, &ssr->subdev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver");
|
MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -12,6 +12,12 @@ struct qcom_rproc_subdev {
|
||||||
struct qcom_smd_edge *edge;
|
struct qcom_smd_edge *edge;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct qcom_rproc_ssr {
|
||||||
|
struct rproc_subdev subdev;
|
||||||
|
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc,
|
struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc,
|
||||||
const struct firmware *fw,
|
const struct firmware *fw,
|
||||||
int *tablesz);
|
int *tablesz);
|
||||||
|
@ -19,4 +25,8 @@ struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc,
|
||||||
void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd);
|
void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd);
|
||||||
void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd);
|
void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd);
|
||||||
|
|
||||||
|
void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
|
||||||
|
const char *ssr_name);
|
||||||
|
void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -153,6 +153,7 @@ struct q6v5 {
|
||||||
size_t mpss_size;
|
size_t mpss_size;
|
||||||
|
|
||||||
struct qcom_rproc_subdev smd_subdev;
|
struct qcom_rproc_subdev smd_subdev;
|
||||||
|
struct qcom_rproc_ssr ssr_subdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int q6v5_regulator_init(struct device *dev, struct reg_info *regs,
|
static int q6v5_regulator_init(struct device *dev, struct reg_info *regs,
|
||||||
|
@ -1038,6 +1039,7 @@ static int q6v5_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
|
qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
|
||||||
|
qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
|
||||||
|
|
||||||
ret = rproc_add(rproc);
|
ret = rproc_add(rproc);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -1058,6 +1060,7 @@ static int q6v5_remove(struct platform_device *pdev)
|
||||||
rproc_del(qproc->rproc);
|
rproc_del(qproc->rproc);
|
||||||
|
|
||||||
qcom_remove_smd_subdev(qproc->rproc, &qproc->smd_subdev);
|
qcom_remove_smd_subdev(qproc->rproc, &qproc->smd_subdev);
|
||||||
|
qcom_remove_ssr_subdev(qproc->rproc, &qproc->ssr_subdev);
|
||||||
rproc_free(qproc->rproc);
|
rproc_free(qproc->rproc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef __QCOM_RPROC_H__
|
||||||
|
#define __QCOM_RPROC_H__
|
||||||
|
|
||||||
|
struct notifier_block;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_QCOM_RPROC_COMMON)
|
||||||
|
|
||||||
|
int qcom_register_ssr_notifier(struct notifier_block *nb);
|
||||||
|
void qcom_unregister_ssr_notifier(struct notifier_block *nb);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int qcom_register_ssr_notifier(struct notifier_block *nb)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void qcom_unregister_ssr_notifier(struct notifier_block *nb) {}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Загрузка…
Ссылка в новой задаче