Commit 92589cbd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rproc-v4.17' of git://github.com/andersson/remoteproc

Pull remoteproc updates from Bjorn Andersson:

 - add support for generating coredumps for remoteprocs using
   devcoredump

 - add the Qualcomm sysmon driver for intra-remoteproc crash handling

 - a number of fixes in Qualcomm and IMX drivers

* tag 'rproc-v4.17' of git://github.com/andersson/remoteproc:
  remoteproc: fix null pointer dereference on glink only platforms
  soc: qcom: qmi: add CONFIG_NET dependency
  remoteproc: imx_rproc: Slightly simplify code in 'imx_rproc_probe()'
  remoteproc: imx_rproc: Re-use existing error handling path in 'imx_rproc_probe()'
  remoteproc: imx_rproc: Fix an error handling path in 'imx_rproc_probe()'
  samples: Introduce Qualcomm QMI sample client
  remoteproc: qcom: Introduce sysmon
  remoteproc: Pass type of shutdown to subdev remove
  remoteproc: qcom: Register segments for core dump
  soc: qcom: mdt-loader: Return relocation base
  remoteproc: Rename "load_rsc_table" to "parse_fw"
  remoteproc: Add remote processor coredump support
  remoteproc: Remove null character write of shared mem
parents 9ab89c40 730b2ad8
...@@ -89,14 +89,14 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname) ...@@ -89,14 +89,14 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname)
*/ */
if (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY) { if (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY) {
ret = qcom_mdt_load(dev, fw, fwname, GPU_PAS_ID, ret = qcom_mdt_load(dev, fw, fwname, GPU_PAS_ID,
mem_region, mem_phys, mem_size); mem_region, mem_phys, mem_size, NULL);
} else { } else {
char newname[strlen("qcom/") + strlen(fwname) + 1]; char newname[strlen("qcom/") + strlen(fwname) + 1];
sprintf(newname, "qcom/%s", fwname); sprintf(newname, "qcom/%s", fwname);
ret = qcom_mdt_load(dev, fw, newname, GPU_PAS_ID, ret = qcom_mdt_load(dev, fw, newname, GPU_PAS_ID,
mem_region, mem_phys, mem_size); mem_region, mem_phys, mem_size, NULL);
} }
if (ret) if (ret)
goto out; goto out;
......
...@@ -76,7 +76,7 @@ int venus_boot(struct device *dev, const char *fwname) ...@@ -76,7 +76,7 @@ int venus_boot(struct device *dev, const char *fwname)
} }
ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys,
mem_size); mem_size, NULL);
release_firmware(mdt); release_firmware(mdt);
......
...@@ -6,6 +6,7 @@ config REMOTEPROC ...@@ -6,6 +6,7 @@ config REMOTEPROC
select CRC32 select CRC32
select FW_LOADER select FW_LOADER
select VIRTIO select VIRTIO
select WANT_DEV_COREDUMP
help help
Support for remote processors (such as DSP coprocessors). These Support for remote processors (such as DSP coprocessors). These
are mainly used on embedded systems. are mainly used on embedded systems.
...@@ -90,6 +91,7 @@ config QCOM_ADSP_PIL ...@@ -90,6 +91,7 @@ config QCOM_ADSP_PIL
depends on QCOM_SMEM depends on QCOM_SMEM
depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON select MFD_SYSCON
select QCOM_MDT_LOADER select QCOM_MDT_LOADER
select QCOM_RPROC_COMMON select QCOM_RPROC_COMMON
...@@ -107,6 +109,7 @@ config QCOM_Q6V5_PIL ...@@ -107,6 +109,7 @@ config QCOM_Q6V5_PIL
depends on QCOM_SMEM depends on QCOM_SMEM
depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON select MFD_SYSCON
select QCOM_RPROC_COMMON select QCOM_RPROC_COMMON
select QCOM_SCM select QCOM_SCM
...@@ -114,12 +117,28 @@ config QCOM_Q6V5_PIL ...@@ -114,12 +117,28 @@ config QCOM_Q6V5_PIL
Say y here to support the Qualcomm Peripherial Image Loader for the Say y here to support the Qualcomm Peripherial Image Loader for the
Hexagon V5 based remote processors. Hexagon V5 based remote processors.
config QCOM_SYSMON
tristate "Qualcomm sysmon driver"
depends on RPMSG
depends on ARCH_QCOM
depends on NET
select QCOM_QMI_HELPERS
help
The sysmon driver implements a sysmon QMI client and a handler for
the sys_mon SMD and GLINK channel, which are used for graceful
shutdown, retrieving failure information and propagating information
about other subsystems being shut down.
Say y here if your system runs firmware on any other subsystems, e.g.
modem or DSP.
config QCOM_WCNSS_PIL config QCOM_WCNSS_PIL
tristate "Qualcomm WCNSS Peripheral Image Loader" tristate "Qualcomm WCNSS Peripheral Image Loader"
depends on OF && ARCH_QCOM depends on OF && ARCH_QCOM
depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SMEM depends on QCOM_SMEM
depends on QCOM_SYSMON || QCOM_SYSMON=n
select QCOM_MDT_LOADER select QCOM_MDT_LOADER
select QCOM_RPROC_COMMON select QCOM_RPROC_COMMON
select QCOM_SCM select QCOM_SCM
......
...@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o ...@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o
obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o
obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o
obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
obj-$(CONFIG_QCOM_SYSMON) += qcom_sysmon.o
obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o
qcom_wcnss_pil-y += qcom_wcnss.o qcom_wcnss_pil-y += qcom_wcnss.o
qcom_wcnss_pil-y += qcom_wcnss_iris.o qcom_wcnss_pil-y += qcom_wcnss_iris.o
......
...@@ -333,14 +333,14 @@ static int imx_rproc_probe(struct platform_device *pdev) ...@@ -333,14 +333,14 @@ static int imx_rproc_probe(struct platform_device *pdev)
/* set some other name then imx */ /* set some other name then imx */
rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops, rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
NULL, sizeof(*priv)); NULL, sizeof(*priv));
if (!rproc) { if (!rproc)
ret = -ENOMEM; return -ENOMEM;
goto err;
}
dcfg = of_device_get_match_data(dev); dcfg = of_device_get_match_data(dev);
if (!dcfg) if (!dcfg) {
return -EINVAL; ret = -EINVAL;
goto err_put_rproc;
}
priv = rproc->priv; priv = rproc->priv;
priv->rproc = rproc; priv->rproc = rproc;
...@@ -359,8 +359,8 @@ static int imx_rproc_probe(struct platform_device *pdev) ...@@ -359,8 +359,8 @@ static int imx_rproc_probe(struct platform_device *pdev)
priv->clk = devm_clk_get(dev, NULL); priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
dev_err(dev, "Failed to get clock\n"); dev_err(dev, "Failed to get clock\n");
rproc_free(rproc); ret = PTR_ERR(priv->clk);
return PTR_ERR(priv->clk); goto err_put_rproc;
} }
/* /*
...@@ -370,8 +370,7 @@ static int imx_rproc_probe(struct platform_device *pdev) ...@@ -370,8 +370,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
ret = clk_prepare_enable(priv->clk); ret = clk_prepare_enable(priv->clk);
if (ret) { if (ret) {
dev_err(&rproc->dev, "Failed to enable clock\n"); dev_err(&rproc->dev, "Failed to enable clock\n");
rproc_free(rproc); goto err_put_rproc;
return ret;
} }
ret = rproc_add(rproc); ret = rproc_add(rproc);
...@@ -380,13 +379,13 @@ static int imx_rproc_probe(struct platform_device *pdev) ...@@ -380,13 +379,13 @@ static int imx_rproc_probe(struct platform_device *pdev)
goto err_put_clk; goto err_put_clk;
} }
return ret; return 0;
err_put_clk: err_put_clk:
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
err_put_rproc: err_put_rproc:
rproc_free(rproc); rproc_free(rproc);
err:
return ret; return ret;
} }
......
...@@ -38,7 +38,10 @@ struct adsp_data { ...@@ -38,7 +38,10 @@ 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; const char *ssr_name;
const char *sysmon_name;
int ssctl_id;
}; };
struct qcom_adsp { struct qcom_adsp {
...@@ -75,6 +78,7 @@ struct qcom_adsp { ...@@ -75,6 +78,7 @@ struct qcom_adsp {
struct qcom_rproc_glink glink_subdev; struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_ssr ssr_subdev; struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
}; };
static int adsp_load(struct rproc *rproc, const struct firmware *fw) static int adsp_load(struct rproc *rproc, const struct firmware *fw)
...@@ -82,7 +86,9 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) ...@@ -82,7 +86,9 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id, return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
adsp->mem_region, adsp->mem_phys, adsp->mem_size); adsp->mem_region, adsp->mem_phys, adsp->mem_size,
&adsp->mem_reloc);
} }
static int adsp_start(struct rproc *rproc) static int adsp_start(struct rproc *rproc)
...@@ -177,6 +183,7 @@ static const struct rproc_ops adsp_ops = { ...@@ -177,6 +183,7 @@ static const struct rproc_ops adsp_ops = {
.start = adsp_start, .start = adsp_start,
.stop = adsp_stop, .stop = adsp_stop,
.da_to_va = adsp_da_to_va, .da_to_va = adsp_da_to_va,
.parse_fw = qcom_register_dump_segments,
.load = adsp_load, .load = adsp_load,
}; };
...@@ -201,9 +208,6 @@ static irqreturn_t adsp_fatal_interrupt(int irq, void *dev) ...@@ -201,9 +208,6 @@ static irqreturn_t adsp_fatal_interrupt(int irq, void *dev)
rproc_report_crash(adsp->rproc, RPROC_FATAL_ERROR); rproc_report_crash(adsp->rproc, RPROC_FATAL_ERROR);
if (!IS_ERR(msg))
msg[0] = '\0';
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -398,6 +402,9 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -398,6 +402,9 @@ static int adsp_probe(struct platform_device *pdev)
qcom_add_glink_subdev(rproc, &adsp->glink_subdev); qcom_add_glink_subdev(rproc, &adsp->glink_subdev);
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); qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name,
desc->ssctl_id);
ret = rproc_add(rproc); ret = rproc_add(rproc);
if (ret) if (ret)
...@@ -419,6 +426,7 @@ static int adsp_remove(struct platform_device *pdev) ...@@ -419,6 +426,7 @@ static int adsp_remove(struct platform_device *pdev)
rproc_del(adsp->rproc); rproc_del(adsp->rproc);
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
qcom_remove_sysmon_subdev(adsp->sysmon);
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); qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
rproc_free(adsp->rproc); rproc_free(adsp->rproc);
...@@ -432,6 +440,8 @@ static const struct adsp_data adsp_resource_init = { ...@@ -432,6 +440,8 @@ static const struct adsp_data adsp_resource_init = {
.pas_id = 1, .pas_id = 1,
.has_aggre2_clk = false, .has_aggre2_clk = false,
.ssr_name = "lpass", .ssr_name = "lpass",
.sysmon_name = "adsp",
.ssctl_id = 0x14,
}; };
static const struct adsp_data slpi_resource_init = { static const struct adsp_data slpi_resource_init = {
...@@ -440,6 +450,8 @@ static const struct adsp_data slpi_resource_init = { ...@@ -440,6 +450,8 @@ static const struct adsp_data slpi_resource_init = {
.pas_id = 12, .pas_id = 12,
.has_aggre2_clk = true, .has_aggre2_clk = true,
.ssr_name = "dsps", .ssr_name = "dsps",
.sysmon_name = "slpi",
.ssctl_id = 0x16,
}; };
static const struct of_device_id adsp_of_match[] = { static const struct of_device_id adsp_of_match[] = {
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/remoteproc.h> #include <linux/remoteproc.h>
#include <linux/rpmsg/qcom_glink.h> #include <linux/rpmsg/qcom_glink.h>
#include <linux/rpmsg/qcom_smd.h> #include <linux/rpmsg/qcom_smd.h>
#include <linux/soc/qcom/mdt_loader.h>
#include "remoteproc_internal.h" #include "remoteproc_internal.h"
#include "qcom_common.h" #include "qcom_common.h"
...@@ -41,7 +42,7 @@ static int glink_subdev_probe(struct rproc_subdev *subdev) ...@@ -41,7 +42,7 @@ static int glink_subdev_probe(struct rproc_subdev *subdev)
return PTR_ERR_OR_ZERO(glink->edge); return PTR_ERR_OR_ZERO(glink->edge);
} }
static void glink_subdev_remove(struct rproc_subdev *subdev) static void glink_subdev_remove(struct rproc_subdev *subdev, bool crashed)
{ {
struct qcom_rproc_glink *glink = to_glink_subdev(subdev); struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
...@@ -74,11 +75,57 @@ EXPORT_SYMBOL_GPL(qcom_add_glink_subdev); ...@@ -74,11 +75,57 @@ EXPORT_SYMBOL_GPL(qcom_add_glink_subdev);
*/ */
void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink) void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
{ {
if (!glink->node)
return;
rproc_remove_subdev(rproc, &glink->subdev); rproc_remove_subdev(rproc, &glink->subdev);
of_node_put(glink->node); of_node_put(glink->node);
} }
EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev); EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev);
/**
* qcom_register_dump_segments() - register segments for coredump
* @rproc: remoteproc handle
* @fw: firmware header
*
* Register all segments of the ELF in the remoteproc coredump segment list
*
* Return: 0 on success, negative errno on failure.
*/
int qcom_register_dump_segments(struct rproc *rproc,
const struct firmware *fw)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
const struct elf32_hdr *ehdr;
int ret;
int i;
ehdr = (struct elf32_hdr *)fw->data;
phdrs = (struct elf32_phdr *)(ehdr + 1);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
if (phdr->p_type != PT_LOAD)
continue;
if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
continue;
if (!phdr->p_memsz)
continue;
ret = rproc_coredump_add_segment(rproc, phdr->p_paddr,
phdr->p_memsz);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_register_dump_segments);
static int smd_subdev_probe(struct rproc_subdev *subdev) static int smd_subdev_probe(struct rproc_subdev *subdev)
{ {
struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
...@@ -88,7 +135,7 @@ static int smd_subdev_probe(struct rproc_subdev *subdev) ...@@ -88,7 +135,7 @@ static int smd_subdev_probe(struct rproc_subdev *subdev)
return PTR_ERR_OR_ZERO(smd->edge); return PTR_ERR_OR_ZERO(smd->edge);
} }
static void smd_subdev_remove(struct rproc_subdev *subdev) static void smd_subdev_remove(struct rproc_subdev *subdev, bool crashed)
{ {
struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
...@@ -121,6 +168,9 @@ EXPORT_SYMBOL_GPL(qcom_add_smd_subdev); ...@@ -121,6 +168,9 @@ EXPORT_SYMBOL_GPL(qcom_add_smd_subdev);
*/ */
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)
{ {
if (!smd->node)
return;
rproc_remove_subdev(rproc, &smd->subdev); rproc_remove_subdev(rproc, &smd->subdev);
of_node_put(smd->node); of_node_put(smd->node);
} }
...@@ -157,7 +207,7 @@ static int ssr_notify_start(struct rproc_subdev *subdev) ...@@ -157,7 +207,7 @@ static int ssr_notify_start(struct rproc_subdev *subdev)
return 0; return 0;
} }
static void ssr_notify_stop(struct rproc_subdev *subdev) static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed)
{ {
struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include <linux/remoteproc.h> #include <linux/remoteproc.h>
#include "remoteproc_internal.h" #include "remoteproc_internal.h"
#include <linux/soc/qcom/qmi.h>
struct qcom_sysmon;
struct qcom_rproc_glink { struct qcom_rproc_glink {
struct rproc_subdev subdev; struct rproc_subdev subdev;
...@@ -30,6 +33,8 @@ struct qcom_rproc_ssr { ...@@ -30,6 +33,8 @@ struct qcom_rproc_ssr {
void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink); void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink);
void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink); void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink);
int qcom_register_dump_segments(struct rproc *rproc, const struct firmware *fw);
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);
...@@ -37,4 +42,22 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, ...@@ -37,4 +42,22 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
const char *ssr_name); const char *ssr_name);
void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr); void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr);
#if IS_ENABLED(CONFIG_QCOM_SYSMON)
struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name,
int ssctl_instance);
void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon);
#else
static inline struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name,
int ssctl_instance)
{
return NULL;
}
static inline void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon)
{
}
#endif
#endif #endif
...@@ -168,6 +168,7 @@ struct q6v5 { ...@@ -168,6 +168,7 @@ struct q6v5 {
struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_ssr ssr_subdev; struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
bool need_mem_protection; bool need_mem_protection;
int mpss_perm; int mpss_perm;
int mba_perm; int mba_perm;
...@@ -939,9 +940,6 @@ static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev) ...@@ -939,9 +940,6 @@ static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
rproc_report_crash(qproc->rproc, RPROC_WATCHDOG); rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
if (!IS_ERR(msg))
msg[0] = '\0';
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -959,9 +957,6 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev) ...@@ -959,9 +957,6 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR); rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
if (!IS_ERR(msg))
msg[0] = '\0';
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1215,6 +1210,7 @@ static int q6v5_probe(struct platform_device *pdev) ...@@ -1215,6 +1210,7 @@ static int q6v5_probe(struct platform_device *pdev)
qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS); qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS);
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"); qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
ret = rproc_add(rproc); ret = rproc_add(rproc);
if (ret) if (ret)
...@@ -1234,6 +1230,7 @@ static int q6v5_remove(struct platform_device *pdev) ...@@ -1234,6 +1230,7 @@ static int q6v5_remove(struct platform_device *pdev)
rproc_del(qproc->rproc); rproc_del(qproc->rproc);
qcom_remove_sysmon_subdev(qproc->sysmon);
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); qcom_remove_ssr_subdev(qproc->rproc, &qproc->ssr_subdev);
rproc_free(qproc->rproc); rproc_free(qproc->rproc);
......
This diff is collapsed.
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define WCNSS_CRASH_REASON_SMEM 422 #define WCNSS_CRASH_REASON_SMEM 422
#define WCNSS_FIRMWARE_NAME "wcnss.mdt" #define WCNSS_FIRMWARE_NAME "wcnss.mdt"
#define WCNSS_PAS_ID 6 #define WCNSS_PAS_ID 6
#define WCNSS_SSCTL_ID 0x13
#define WCNSS_SPARE_NVBIN_DLND BIT(25) #define WCNSS_SPARE_NVBIN_DLND BIT(25)
...@@ -98,6 +99,7 @@ struct qcom_wcnss { ...@@ -98,6 +99,7 @@ struct qcom_wcnss {
size_t mem_size; size_t mem_size;
struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_subdev smd_subdev;
struct qcom_sysmon *sysmon;
}; };
static const struct wcnss_data riva_data = { static const struct wcnss_data riva_data = {
...@@ -153,7 +155,8 @@ static int wcnss_load(struct rproc *rproc, const struct firmware *fw) ...@@ -153,7 +155,8 @@ static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID, return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
wcnss->mem_region, wcnss->mem_phys, wcnss->mem_size); wcnss->mem_region, wcnss->mem_phys,
wcnss->mem_size, &wcnss->mem_reloc);
} }
static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss) static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
...@@ -308,6 +311,7 @@ static const struct rproc_ops wcnss_ops = { ...@@ -308,6 +311,7 @@ static const struct rproc_ops wcnss_ops = {
.start = wcnss_start, .start = wcnss_start,
.stop = wcnss_stop, .stop = wcnss_stop,
.da_to_va = wcnss_da_to_va, .da_to_va = wcnss_da_to_va,
.parse_fw = qcom_register_dump_segments,
.load = wcnss_load, .load = wcnss_load,
}; };
...@@ -332,9 +336,6 @@ static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev) ...@@ -332,9 +336,6 @@ static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev)
rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR); rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR);
if (!IS_ERR(msg))
msg[0] = '\0';
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -551,6 +552,7 @@ static int wcnss_probe(struct platform_device *pdev) ...@@ -551,6 +552,7 @@ static int wcnss_probe(struct platform_device *pdev)
} }
qcom_add_smd_subdev(rproc, &wcnss->smd_subdev); qcom_add_smd_subdev(rproc, &wcnss->smd_subdev);
wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID);
ret = rproc_add(rproc); ret = rproc_add(rproc);
if (ret) if (ret)
...@@ -573,6 +575,7 @@ static int wcnss_remove(struct platform_device *pdev) ...@@ -573,6 +575,7 @@ static int wcnss_remove(struct platform_device *pdev)
qcom_smem_state_put(wcnss->state); qcom_smem_state_put(wcnss->state);
rproc_del(wcnss->rproc); rproc_del(wcnss->rproc);
qcom_remove_sysmon_subdev(wcnss->sysmon);
qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev); qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev);
rproc_free(wcnss->rproc); rproc_free(wcnss->rproc);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/devcoredump.h>
#include <linux/remoteproc.h> #include <linux/remoteproc.h>
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/idr.h> #include <linux/idr.h>
...@@ -307,7 +308,7 @@ static int rproc_vdev_do_probe(struct rproc_subdev *subdev) ...@@ -307,7 +308,7 @@ static int rproc_vdev_do_probe(struct rproc_subdev *subdev)
return rproc_add_virtio_dev(rvdev, rvdev->id); return rproc_add_virtio_dev(rvdev, rvdev->id);
} }
static void rproc_vdev_do_remove(struct rproc_subdev *subdev) static void rproc_vdev_do_remove(struct rproc_subdev *subdev, bool crashed)
{ {
struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev); struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
...@@ -788,17 +789,31 @@ static int rproc_probe_subdevices(struct rproc *rproc) ...@@ -788,17 +789,31 @@ static int rproc_probe_subdevices(struct rproc *rproc)
unroll_registration: unroll_registration:
list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node) list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node)
subdev->remove(subdev); subdev->remove(subdev, true);
return ret; return ret;
} }
static void rproc_remove_subdevices(struct rproc *rproc) static void rproc_remove_subdevices(struct rproc *rproc, bool crashed)
{ {
struct rproc_subdev *subdev; struct rproc_subdev *subdev;
list_for_each_entry_reverse(subdev, &rproc->subdevs, node) list_for_each_entry_reverse(subdev, &rproc->subdevs, node)
subdev->remove(subdev); subdev->remove(subdev, crashed);
}
/**
* rproc_coredump_cleanup() - clean up dump_segments list
* @rproc: the remote processor handle
*/
static void rproc_coredump_cleanup(struct rproc *rproc)
{
struct rproc_dump_segment *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &rproc->dump_segments, node) {
list_del(&entry->node);
kfree(entry);
}
} }
/** /**
...@@ -848,6 +863,8 @@ static void rproc_resource_cleanup(struct rproc *rproc) ...@@ -848,6 +863,8 @@ static void rproc_resource_cleanup(struct rproc *rproc)
/* clean up remote vdev entries */ /* clean up remote vdev entries */
list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
kref_put(&rvdev->refcount, rproc_vdev_release); kref_put(&rvdev->refcount, rproc_vdev_release);
rproc_coredump_cleanup(rproc);
} }
static int rproc_start(struct rproc *rproc, const struct firmware *fw) static int rproc_start(struct rproc *rproc, const struct firmware *fw)
...@@ -927,8 +944,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) ...@@ -927,8 +944,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
rproc->bootaddr = rproc_get_boot_addr(rproc, fw); rproc->bootaddr = rproc_get_boot_addr(rproc, fw);
/* load resource table */ /* Load resource table, core dump segment list etc from the firmware */
ret = rproc_load_rsc_table(rproc, fw); ret = rproc_parse_fw(rproc, fw);
if (ret) if (ret)
goto disable_iommu; goto disable_iommu;
...@@ -992,13 +1009,13 @@ static int rproc_trigger_auto_boot(struct rproc *rproc) ...@@ -992,13 +1009,13 @@ static int rproc_trigger_auto_boot(struct rproc *rproc)
return ret; return ret;
} }
static int rproc_stop(struct rproc *rproc) static int rproc_stop(struct rproc *rproc, bool crashed)
{ {
struct device *dev = &rproc->dev; struct device *dev = &rproc->dev;
int ret; int ret;
/* remove any subdevices for the remote processor */ /* remove any subdevices for the remote processor */
rproc_remove_subdevices(rproc); rproc_remove_subdevices(rproc, crashed);
/* the installed resource table is no longer accessible */ /* the installed resource table is no longer accessible */
rproc->table_ptr = rproc->cached_table; rproc->table_ptr = rproc->cached_table;
...@@ -1017,6 +1034,113 @@ static int rproc_stop(struct rproc *rproc) ...@@ -1017,6 +1034,113 @@ static int rproc_stop(struct rproc *rproc)
return 0; return 0;
} }
/**
* rproc_coredump_add_segment() - add segment of device memory to coredump
* @rproc: handle of a remote processor
* @da: device address
* @size: size of segment
*
* Add device memory to the list of segments to be included in a coredump for
* the remoteproc.
*
* Return: 0 on success, negative errno on error.
*/
int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size)
{
struct rproc_dump_segment *segment;
segment = kzalloc(sizeof(*segment), GFP_KERNEL);
if (!segment)
return -ENOMEM;
segment->da = da;
segment->size = size;
list_add_tail(&segment->node, &rproc->dump_segments);
return 0;
}
EXPORT_SYMBOL(rproc_coredump_add_segment);
/**
* rproc_coredump() - perform coredump
* @rproc: rproc handle
*
* This function will generate an ELF header for the registered segments
* and create a devcoredump device associated with rproc.
*/
static void rproc_coredump(struct rproc *rproc)
{
struct rproc_dump_segment *segment;
struct elf32_phdr *phdr;
struct elf32_hdr *ehdr;
size_t data_size;
size_t offset;
void *data;
void *ptr;
int phnum = 0;
if (list_empty(&rproc->dump_segments))
return;
data_size = sizeof(*ehdr);
list_for_each_entry(segment, &rproc->dump_segments, node) {
data_size += sizeof(*phdr) + segment->size;
phnum++;
}
data = vmalloc(data_size);
if (!data)
return;
ehdr = data;
memset(ehdr, 0, sizeof(*ehdr));
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
ehdr->e_ident[EI_CLASS] = ELFCLASS32;
ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
ehdr->e_type = ET_CORE;
ehdr->e_machine = EM_NONE;
ehdr->e_version = EV_CURRENT;
ehdr->e_entry = rproc->bootaddr;
ehdr->e_phoff = sizeof(*ehdr);
ehdr->e_ehsize = sizeof(*ehdr);
ehdr->e_phentsize = sizeof(*phdr);
ehdr->e_phnum = phnum;
phdr = data + ehdr->e_phoff;
offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
list_for_each_entry(segment, &rproc->dump_segments, node) {
memset(phdr, 0, sizeof(*phdr));
phdr->p_type = PT_LOAD;
phdr->p_offset = offset;
phdr->p_vaddr = segment->da;
phdr->p_paddr = segment->da;
phdr->p_filesz = segment->size;
phdr->p_memsz = segment->size;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_align = 0;
ptr = rproc_da_to_va(rproc, segment->da, segment->size);
if (!ptr) {
dev_err(&rproc->dev,
"invalid coredump segment (%pad, %zu)\n",
&segment->da, segment->size);
memset(data + offset, 0xff, segment->size);
} else {
memcpy(data + offset, ptr, segment->size);
}
offset += phdr->p_filesz;
phdr++;
}
dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
}
/** /**
* rproc_trigger_recovery() - recover a remoteproc * rproc_trigger_recovery() - recover a remoteproc
* @rproc: the remote processor * @rproc: the remote processor
...@@ -1039,10 +1163,13 @@ int rproc_trigger_recovery(struct rproc *rproc) ...@@ -1039,10 +1163,13 @@ int rproc_trigger_recovery(struct rproc *rproc)
if (ret) if (ret)
return ret; return ret;
ret = rproc_stop(rproc); ret = rproc_stop(rproc, false);
if (ret) if (ret)
goto unlock_mutex; goto unlock_mutex;
/* generate coredump */
rproc_coredump(rproc);
/* load firmware */ /* load firmware */
ret = request_firmware(&firmware_p, rproc->firmware, dev); ret = request_firmware(&firmware_p, rproc->firmware, dev);
if (ret < 0) { if (ret < 0) {
...@@ -1189,7 +1316,7 @@ void rproc_shutdown(struct rproc *rproc) ...@@ -1189,7 +1316,7 @@ void rproc_shutdown(struct rproc *rproc)
if (!atomic_dec_and_test(&rproc->power)) if (!atomic_dec_and_test(&rproc->power))
goto out; goto out;
ret = rproc_stop(rproc); ret = rproc_stop(rproc, true);
if (ret) { if (ret) {
atomic_inc(&rproc->power); atomic_inc(&rproc->power);
goto out; goto out;
...@@ -1428,7 +1555,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, ...@@ -1428,7 +1555,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
/* Default to ELF loader if no load function is specified */ /* Default to ELF loader if no load function is specified */
if (!rproc->ops->load) { if (!rproc->ops->load) {
rproc->ops->load = rproc_elf_load_segments; rproc->ops->load = rproc_elf_load_segments;
rproc->ops->load_rsc_table = rproc_elf_load_rsc_table; rproc->ops->parse_fw = rproc_elf_load_rsc_table;
rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table; rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table;
rproc->ops->sanity_check = rproc_elf_sanity_check; rproc->ops->sanity_check = rproc_elf_sanity_check;
rproc->ops->get_boot_addr = rproc_elf_get_boot_addr; rproc->ops->get_boot_addr = rproc_elf_get_boot_addr;
...@@ -1443,6 +1570,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, ...@@ -1443,6 +1570,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
INIT_LIST_HEAD(&rproc->traces); INIT_LIST_HEAD(&rproc->traces);
INIT_LIST_HEAD(&rproc->rvdevs); INIT_LIST_HEAD(&rproc->rvdevs);
INIT_LIST_HEAD(&rproc->subdevs); INIT_LIST_HEAD(&rproc->subdevs);
INIT_LIST_HEAD(&rproc->dump_segments);
INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work); INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
...@@ -1535,7 +1663,7 @@ EXPORT_SYMBOL(rproc_del); ...@@ -1535,7 +1663,7 @@ EXPORT_SYMBOL(rproc_del);
void rproc_add_subdev(struct rproc *rproc, void rproc_add_subdev(struct rproc *rproc,
struct rproc_subdev *subdev, struct rproc_subdev *subdev,
int (*probe)(struct rproc_subdev *subdev), int (*probe)(struct rproc_subdev *subdev),
void (*remove)(struct rproc_subdev *subdev)) void (*remove)(struct rproc_subdev *subdev, bool crashed))
{ {
subdev->probe = probe; subdev->probe = probe;
subdev->remove = remove; subdev->remove = remove;
......
...@@ -88,11 +88,10 @@ int rproc_load_segments(struct rproc *rproc, const struct firmware *fw) ...@@ -88,11 +88,10 @@ int rproc_load_segments(struct rproc *rproc, const struct firmware *fw)
return -EINVAL; return -EINVAL;
} }
static inline int rproc_load_rsc_table(struct rproc *rproc, static inline int rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
const struct firmware *fw)
{ {
if (rproc->ops->load_rsc_table) if (rproc->ops->parse_fw)
return rproc->ops->load_rsc_table(rproc, fw); return rproc->ops->parse_fw(rproc, fw);
return 0; return 0;
} }
......
...@@ -37,7 +37,7 @@ config QCOM_PM ...@@ -37,7 +37,7 @@ config QCOM_PM
config QCOM_QMI_HELPERS config QCOM_QMI_HELPERS
tristate tristate
depends on ARCH_QCOM depends on ARCH_QCOM && NET
help help
Helper library for handling QMI encoded messages. QMI encoded Helper library for handling QMI encoded messages. QMI encoded
messages are used in communication between the majority of QRTR messages are used in communication between the majority of QRTR
......
...@@ -83,12 +83,14 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size); ...@@ -83,12 +83,14 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
* @mem_region: allocated memory region to load firmware into * @mem_region: allocated memory region to load firmware into
* @mem_phys: physical address of allocated memory region * @mem_phys: physical address of allocated memory region
* @mem_size: size of the allocated memory region * @mem_size: size of the allocated memory region
* @reloc_base: adjusted physical address after relocation
* *
* Returns 0 on success, negative errno otherwise. * Returns 0 on success, negative errno otherwise.
*/ */
int qcom_mdt_load(struct device *dev, const struct firmware *fw, int qcom_mdt_load(struct device *dev, const struct firmware *fw,
const char *firmware, int pas_id, void *mem_region, const char *firmware, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size) phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base)
{ {
const struct elf32_phdr *phdrs; const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr; const struct elf32_phdr *phdr;
...@@ -192,6 +194,9 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, ...@@ -192,6 +194,9 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
} }
if (reloc_base)
*reloc_base = mem_reloc;
out: out:
kfree(fw_name); kfree(fw_name);
......
...@@ -344,7 +344,7 @@ struct rproc_ops { ...@@ -344,7 +344,7 @@ struct rproc_ops {
int (*stop)(struct rproc *rproc); int (*stop)(struct rproc *rproc);
void (*kick)(struct rproc *rproc, int vqid); void (*kick)(struct rproc *rproc, int vqid);
void * (*da_to_va)(struct rproc *rproc, u64 da, int len); void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
int (*load_rsc_table)(struct rproc *rproc, const struct firmware *fw); int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
struct resource_table *(*find_loaded_rsc_table)( struct resource_table *(*find_loaded_rsc_table)(
struct rproc *rproc, const struct firmware *fw); struct rproc *rproc, const struct firmware *fw);
int (*load)(struct rproc *rproc, const struct firmware *fw); int (*load)(struct rproc *rproc, const struct firmware *fw);
...@@ -394,6 +394,21 @@ enum rproc_crash_type { ...@@ -394,6 +394,21 @@ enum rproc_crash_type {
RPROC_FATAL_ERROR, RPROC_FATAL_ERROR,
}; };
/**
* struct rproc_dump_segment - segment info from ELF header
* @node: list node related to the rproc segment list
* @da: device address of the segment
* @size: size of the segment
*/
struct rproc_dump_segment {
struct list_head node;
dma_addr_t da;
size_t size;
loff_t offset;
};
/** /**
* struct rproc - represents a physical remote processor device * struct rproc - represents a physical remote processor device
* @node: list node of this rproc object * @node: list node of this rproc object
...@@ -424,6 +439,7 @@ enum rproc_crash_type { ...@@ -424,6 +439,7 @@ enum rproc_crash_type {
* @cached_table: copy of the resource table * @cached_table: copy of the resource table
* @table_sz: size of @cached_table * @table_sz: size of @cached_table
* @has_iommu: flag to indicate if remote processor is behind an MMU * @has_iommu: flag to indicate if remote processor is behind an MMU
* @dump_segments: list of segments in the firmware
*/ */
struct rproc { struct rproc {
struct list_head node; struct list_head node;
...@@ -455,19 +471,21 @@ struct rproc { ...@@ -455,19 +471,21 @@ struct rproc {
size_t table_sz; size_t table_sz;
bool has_iommu; bool has_iommu;
bool auto_boot; bool auto_boot;
struct list_head dump_segments;
}; };
/** /**
* struct rproc_subdev - subdevice tied to a remoteproc * struct rproc_subdev - subdevice tied to a remoteproc
* @node: list node related to the rproc subdevs list * @node: list node related to the rproc subdevs list
* @probe: probe function, called as the rproc is started * @probe: probe function, called as the rproc is started
* @remove: remove function, called as the rproc is stopped * @remove: remove function, called as the rproc is being stopped, the @crashed
* parameter indicates if this originates from the a recovery
*/ */
struct rproc_subdev { struct rproc_subdev {
struct list_head node; struct list_head node;
int (*probe)(struct rproc_subdev *subdev); int (*probe)(struct rproc_subdev *subdev);
void (*remove)(struct rproc_subdev *subdev); void (*remove)(struct rproc_subdev *subdev, bool crashed);
}; };
/* we currently support only two vrings per rvdev */ /* we currently support only two vrings per rvdev */
...@@ -534,6 +552,7 @@ void rproc_free(struct rproc *rproc); ...@@ -534,6 +552,7 @@ void rproc_free(struct rproc *rproc);
int rproc_boot(struct rproc *rproc); int rproc_boot(struct rproc *rproc);
void rproc_shutdown(struct rproc *rproc); void rproc_shutdown(struct rproc *rproc);
void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size);
static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev) static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
{ {
...@@ -550,7 +569,7 @@ static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev) ...@@ -550,7 +569,7 @@ static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
void rproc_add_subdev(struct rproc *rproc, void rproc_add_subdev(struct rproc *rproc,
struct rproc_subdev *subdev, struct rproc_subdev *subdev,
int (*probe)(struct rproc_subdev *subdev), int (*probe)(struct rproc_subdev *subdev),
void (*remove)(struct rproc_subdev *subdev)); void (*remove)(struct rproc_subdev *subdev, bool graceful));
void rproc_remove_subdev(struct rproc *rproc, struct rproc_subdev *subdev); void rproc_remove_subdev(struct rproc *rproc, struct rproc_subdev *subdev);
......
...@@ -14,6 +14,7 @@ struct firmware; ...@@ -14,6 +14,7 @@ struct firmware;
ssize_t qcom_mdt_get_size(const struct firmware *fw); ssize_t qcom_mdt_get_size(const struct firmware *fw);
int qcom_mdt_load(struct device *dev, const struct firmware *fw, int qcom_mdt_load(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, void *mem_region, const char *fw_name, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size); phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base);
#endif #endif
...@@ -62,6 +62,16 @@ config SAMPLE_KDB ...@@ -62,6 +62,16 @@ config SAMPLE_KDB
Build an example of how to dynamically add the hello Build an example of how to dynamically add the hello
command to the kdb shell. command to the kdb shell.
config SAMPLE_QMI_CLIENT
tristate "Build qmi client sample -- loadable modules only"
depends on m
depends on ARCH_QCOM
depends on NET
select QCOM_QMI_HELPERS
help
Build an QMI client sample driver, which demonstrates how to
communicate with a remote QRTR service, using QMI encoded messages.
config SAMPLE_RPMSG_CLIENT config SAMPLE_RPMSG_CLIENT
tristate "Build rpmsg client sample -- loadable modules only" tristate "Build rpmsg client sample -- loadable modules only"
depends on RPMSG && m depends on RPMSG && m
......
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \
hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
configfs/ connector/ v4l/ trace_printk/ \ configfs/ connector/ v4l/ trace_printk/ \
vfio-mdev/ statx/ vfio-mdev/ statx/ qmi/
obj-$(CONFIG_SAMPLE_QMI_CLIENT) += qmi_sample_client.o
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment