2020-02-11 00:52:30

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 0/8] remoteproc: qcom: post mortem debug support

The following series introduces two components that aids in post mortem
debugging of Qualcomm systems. The first part is used to store information
about loaded images in IMEM, for post mortem tools to know where the kernel
loaded the remoteproc firmware. The second part invokes a stop operation on the
remoteprocs during a kernel panic, in order to trigger them to flush caches
etc.

Bjorn Andersson (8):
dt-bindings: remoteproc: Add Qualcomm PIL info binding
remoteproc: qcom: Introduce driver to store pil info in IMEM
remoteproc: qcom: Update IMEM PIL info on load
arm64: dts: qcom: qcs404: Add IMEM and PIL info region
arm64: dts: qcom: sdm845: Add IMEM and PIL info region
remoteproc: Introduce "panic" callback in ops
remoteproc: qcom: q6v5: Add common panic handler
remoteproc: qcom: Introduce panic handler for PAS and ADSP

.../bindings/remoteproc/qcom,pil-info.yaml | 42 +++++
arch/arm64/boot/dts/qcom/qcs404.dtsi | 13 ++
arch/arm64/boot/dts/qcom/sdm845.dtsi | 13 ++
drivers/remoteproc/Kconfig | 6 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/qcom_pil_info.c | 168 ++++++++++++++++++
drivers/remoteproc/qcom_pil_info.h | 8 +
drivers/remoteproc/qcom_q6v5.c | 20 +++
drivers/remoteproc/qcom_q6v5.h | 1 +
drivers/remoteproc/qcom_q6v5_adsp.c | 27 ++-
drivers/remoteproc/qcom_q6v5_mss.c | 6 +
drivers/remoteproc/qcom_q6v5_pas.c | 26 ++-
drivers/remoteproc/qcom_wcnss.c | 17 +-
drivers/remoteproc/remoteproc_core.c | 46 +++++
include/linux/remoteproc.h | 3 +
15 files changed, 388 insertions(+), 9 deletions(-)
create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
create mode 100644 drivers/remoteproc/qcom_pil_info.c
create mode 100644 drivers/remoteproc/qcom_pil_info.h

--
2.24.0


2020-02-11 00:52:46

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 4/8] arm64: dts: qcom: qcs404: Add IMEM and PIL info region

Add a simple-mfd representing IMEM on QCS404 and define the PIL
relocation info region, so that post mortem tools will be able to locate
the loaded remoteprocs.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Replace offset with reg

arch/arm64/boot/dts/qcom/qcs404.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
index 4ee1e3d5f123..f539293b875c 100644
--- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
@@ -997,6 +997,19 @@ blsp2_spi0: spi@7af5000 {
status = "disabled";
};

+ imem@8600000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x08600000 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pil-reloc@94c {
+ compatible ="qcom,pil-reloc-info";
+ reg = <0x94c 200>;
+ };
+ };
+
intc: interrupt-controller@b000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
--
2.24.0

2020-02-11 00:52:49

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 6/8] remoteproc: Introduce "panic" callback in ops

Introduce a "panic" function in the remoteproc ops table, to allow
remoteproc instances to perform operations needed in order to aid in
post mortem system debugging, such as flushing caches etc, when the
kernel panics. The function can return a number of milliseconds needed
by the remote to "settle" and the core will wait the longest returned
duration before returning from the panic handler.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Replace per-rproc notifier callback with one generic
- Move the mdelay() from the individual drivers to the core and sleep the
longest returned duration. Drivers that doesn't need a delay can return 0.
- Unregister the notifier on exit

drivers/remoteproc/remoteproc_core.c | 46 ++++++++++++++++++++++++++++
include/linux/remoteproc.h | 3 ++
2 files changed, 49 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 097f33e4f1f3..8b6932027d36 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -16,6 +16,7 @@

#define pr_fmt(fmt) "%s: " fmt, __func__

+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -43,6 +44,7 @@

static DEFINE_MUTEX(rproc_list_mutex);
static LIST_HEAD(rproc_list);
+static struct notifier_block rproc_panic_nb;

typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
void *, int offset, int avail);
@@ -2216,10 +2218,53 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
}
EXPORT_SYMBOL(rproc_report_crash);

+static int rproc_panic_handler(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+{
+ unsigned int longest = 0;
+ struct rproc *rproc;
+ unsigned int d;
+ int locked;
+
+ locked = mutex_trylock(&rproc_list_mutex);
+ if (!locked) {
+ pr_err("Failed to acquire rproc list lock, won't call panic functions\n");
+ return NOTIFY_DONE;
+ }
+
+ list_for_each_entry(rproc, &rproc_list, node) {
+ if (!rproc->ops->panic || rproc->state != RPROC_RUNNING)
+ continue;
+
+ d = rproc->ops->panic(rproc);
+ if (d > longest)
+ longest = d;
+ }
+
+ mutex_unlock(&rproc_list_mutex);
+
+ /* Delay panic for the longest requested duration */
+ mdelay(longest);
+
+ return NOTIFY_DONE;
+}
+
+static void __init rproc_init_panic(void)
+{
+ rproc_panic_nb.notifier_call = rproc_panic_handler;
+ atomic_notifier_chain_register(&panic_notifier_list, &rproc_panic_nb);
+}
+
+static void __exit rproc_exit_panic(void)
+{
+ atomic_notifier_chain_unregister(&panic_notifier_list, &rproc_panic_nb);
+}
+
static int __init remoteproc_init(void)
{
rproc_init_sysfs();
rproc_init_debugfs();
+ rproc_init_panic();

return 0;
}
@@ -2229,6 +2274,7 @@ static void __exit remoteproc_exit(void)
{
ida_destroy(&rproc_dev_index);

+ rproc_exit_panic();
rproc_exit_debugfs();
rproc_exit_sysfs();
}
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 16ad66683ad0..14f05f26cbcd 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -369,6 +369,8 @@ enum rsc_handling_status {
* expects to find it
* @sanity_check: sanity check the fw image
* @get_boot_addr: get boot address to entry point specified in firmware
+ * @panic: optional callback to react to system panic, core will delay
+ * panic at least the returned number of milliseconds
*/
struct rproc_ops {
int (*start)(struct rproc *rproc);
@@ -383,6 +385,7 @@ struct rproc_ops {
int (*load)(struct rproc *rproc, const struct firmware *fw);
int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+ unsigned int (*panic)(struct rproc *rproc);
};

/**
--
2.24.0

2020-02-11 00:52:51

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 8/8] remoteproc: qcom: Introduce panic handler for PAS and ADSP

Make the PAS and ADSP/CDSP remoteproc drivers implement the panic
handler that will invoke a stop to prepare the remoteprocs for post
mortem debugging.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Update return type and pass the return value through

drivers/remoteproc/qcom_q6v5_adsp.c | 8 ++++++++
drivers/remoteproc/qcom_q6v5_pas.c | 8 ++++++++
2 files changed, 16 insertions(+)

diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index 19f784adf91c..822881534d37 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -291,12 +291,20 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
return adsp->mem_region + offset;
}

+static unsigned int adsp_panic(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+
+ return qcom_q6v5_panic(&adsp->q6v5);
+}
+
static const struct rproc_ops adsp_ops = {
.start = adsp_start,
.stop = adsp_stop,
.da_to_va = adsp_da_to_va,
.parse_fw = qcom_register_dump_segments,
.load = adsp_load,
+ .panic = adsp_panic,
};

static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index d20ce3c62256..ac38624fb14d 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -242,12 +242,20 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
return adsp->mem_region + offset;
}

+static unsigned int adsp_panic(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+
+ return qcom_q6v5_panic(&adsp->q6v5);
+}
+
static const struct rproc_ops adsp_ops = {
.start = adsp_start,
.stop = adsp_stop,
.da_to_va = adsp_da_to_va,
.parse_fw = qcom_register_dump_segments,
.load = adsp_load,
+ .panic = adsp_panic,
};

static int adsp_init_clock(struct qcom_adsp *adsp)
--
2.24.0

2020-02-11 00:52:55

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 5/8] arm64: dts: qcom: sdm845: Add IMEM and PIL info region

Add a simple-mfd representing IMEM on SDM845 and define the PIL
relocation info region, so that post mortem tools will be able to locate
the loaded remoteprocs.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Replace offset with reg

arch/arm64/boot/dts/qcom/sdm845.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index d42302b8889b..3443d989976c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -3018,6 +3018,19 @@ spmi_bus: spmi@c440000 {
cell-index = <0>;
};

+ imem@146bf000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0 0x146bf000 0 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pil-reloc@94c {
+ compatible ="qcom,pil-reloc-info";
+ reg = <0x94c 200>;
+ };
+ };
+
apps_smmu: iommu@15000000 {
compatible = "qcom,sdm845-smmu-500", "arm,mmu-500";
reg = <0 0x15000000 0 0x80000>;
--
2.24.0

2020-02-11 00:53:04

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 7/8] remoteproc: qcom: q6v5: Add common panic handler

Add a common panic handler that invokes a stop request and sleep enough
to let the remoteproc flush it's caches etc in order to aid post mortem
debugging. For now a hard coded 200ms is returned to the remoteproc
core, this value is taken from the downstream kernel.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Update return type and return the delay

drivers/remoteproc/qcom_q6v5.c | 20 ++++++++++++++++++++
drivers/remoteproc/qcom_q6v5.h | 1 +
2 files changed, 21 insertions(+)

diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index cb0f4a0be032..6bf660ad889c 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -15,6 +15,8 @@
#include <linux/remoteproc.h>
#include "qcom_q6v5.h"

+#define Q6V5_PANIC_DELAY_MS 200
+
/**
* qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
* @q6v5: reference to qcom_q6v5 context to be reinitialized
@@ -162,6 +164,24 @@ int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5)
}
EXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);

+/**
+ * qcom_q6v5_panic() - panic handler to invoke a stop on the remote
+ * @q6v5: reference to qcom_q6v5 context
+ *
+ * Set the stop bit and sleep in order to allow the remote processor to flush
+ * its caches etc for post mortem debugging.
+ *
+ * Return: 200ms
+ */
+unsigned int qcom_q6v5_panic(struct qcom_q6v5 *q6v5)
+{
+ qcom_smem_state_update_bits(q6v5->state,
+ BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
+
+ return Q6V5_PANIC_DELAY_MS;
+}
+EXPORT_SYMBOL_GPL(qcom_q6v5_panic);
+
/**
* qcom_q6v5_init() - initializer of the q6v5 common struct
* @q6v5: handle to be initialized
diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h
index 7ac92c1e0f49..3bef8243b33b 100644
--- a/drivers/remoteproc/qcom_q6v5.h
+++ b/drivers/remoteproc/qcom_q6v5.h
@@ -42,5 +42,6 @@ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5);
int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5);
int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5);
int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout);
+unsigned int qcom_q6v5_panic(struct qcom_q6v5 *q6v5);

#endif
--
2.24.0

2020-02-11 00:53:50

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 1/8] dt-bindings: remoteproc: Add Qualcomm PIL info binding

Add a devicetree binding for the Qualcomm periperal image loader
relocation info region found in the IMEM.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Replaced offset with reg to describe the region of IMEM used for the entries

.../bindings/remoteproc/qcom,pil-info.yaml | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml

diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
new file mode 100644
index 000000000000..8386a4da6030
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,pil-info.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm peripheral image loader relocation info binding
+
+maintainers:
+ - Bjorn Andersson <[email protected]>
+
+description:
+ This document defines the binding for describing the Qualcomm peripheral
+ image loader relocation memory region, in IMEM, which is used for post mortem
+ debugging of remoteprocs.
+
+properties:
+ compatible:
+ const: qcom,pil-reloc-info
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ imem@146bf000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0 0x146bf000 0 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pil-reloc {
+ compatible ="qcom,pil-reloc-info";
+ reg = <0x94c 200>;
+ };
+ };
+...
--
2.24.0

2020-02-11 00:54:25

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 2/8] remoteproc: qcom: Introduce driver to store pil info in IMEM

A region in IMEM is used to communicate load addresses of remoteproc to
post mortem debug tools. Implement a driver that can be used to store
this information in order to enable these tools to process collected
ramdumps.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Sorted includes
- Replace use of stracpy (still not landed upstream)
- Fixed error handling in probe
- Return error from store, to allow clients to decide action
- Replace hard coded size with value read from reg property

drivers/remoteproc/Kconfig | 3 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/qcom_pil_info.c | 168 +++++++++++++++++++++++++++++
drivers/remoteproc/qcom_pil_info.h | 8 ++
4 files changed, 180 insertions(+)
create mode 100644 drivers/remoteproc/qcom_pil_info.c
create mode 100644 drivers/remoteproc/qcom_pil_info.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index de3862c15fcc..20c8194e610e 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -95,6 +95,9 @@ config KEYSTONE_REMOTEPROC
It's safe to say N here if you're not interested in the Keystone
DSPs or just want to use a bare minimum kernel.

+config QCOM_PIL_INFO
+ tristate
+
config QCOM_RPROC_COMMON
tristate

diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index e30a1b15fbac..2ab32bd41b44 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o
+obj-$(CONFIG_QCOM_PIL_INFO) += qcom_pil_info.o
obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o
obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o
obj-$(CONFIG_QCOM_Q6V5_ADSP) += qcom_q6v5_adsp.o
diff --git a/drivers/remoteproc/qcom_pil_info.c b/drivers/remoteproc/qcom_pil_info.c
new file mode 100644
index 000000000000..398aeb957f3c
--- /dev/null
+++ b/drivers/remoteproc/qcom_pil_info.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020 Linaro Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define PIL_RELOC_NAME_LEN 8
+
+struct pil_reloc_entry {
+ char name[PIL_RELOC_NAME_LEN];
+ __le64 base;
+ __le32 size;
+} __packed;
+
+struct pil_reloc {
+ struct device *dev;
+ struct regmap *map;
+ size_t offset;
+ size_t num_entries;
+ int val_bytes;
+
+ struct pil_reloc_entry entries[];
+};
+
+static struct pil_reloc *_reloc;
+static DEFINE_MUTEX(reloc_mutex);
+
+/**
+ * qcom_pil_info_store() - store PIL information of image in IMEM
+ * @image: name of the image
+ * @base: base address of the loaded image
+ * @size: size of the loaded image
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size)
+{
+ struct pil_reloc_entry *entry;
+ int idx = -1;
+ int ret;
+ int i;
+
+ mutex_lock(&reloc_mutex);
+ for (i = 0; i < _reloc->num_entries; i++) {
+ if (!_reloc->entries[i].name[0]) {
+ if (idx == -1)
+ idx = i;
+ continue;
+ }
+
+ if (!strncmp(_reloc->entries[i].name, image, 8)) {
+ idx = i;
+ goto found;
+ }
+ }
+
+ if (idx == -1) {
+ dev_warn(_reloc->dev, "insufficient PIL info slots\n");
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+found:
+ entry = &_reloc->entries[idx];
+ strscpy(entry->name, image, ARRAY_SIZE(entry->name));
+ entry->base = base;
+ entry->size = size;
+
+ ret = regmap_bulk_write(_reloc->map,
+ _reloc->offset + idx * sizeof(*entry),
+ entry, sizeof(*entry) / _reloc->val_bytes);
+unlock:
+ mutex_unlock(&reloc_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_pil_info_store);
+
+/**
+ * qcom_pil_info_available() - query if the pil info is probed
+ *
+ * Return: boolean indicating if the pil info device is probed
+ */
+bool qcom_pil_info_available(void)
+{
+ return !!_reloc;
+}
+EXPORT_SYMBOL_GPL(qcom_pil_info_available);
+
+static int pil_reloc_probe(struct platform_device *pdev)
+{
+ unsigned int num_entries;
+ struct pil_reloc *reloc;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ num_entries = resource_size(res) / sizeof(struct pil_reloc_entry);
+
+ reloc = devm_kzalloc(&pdev->dev,
+ struct_size(reloc, entries, num_entries),
+ GFP_KERNEL);
+ if (!reloc)
+ return -ENOMEM;
+
+ reloc->dev = &pdev->dev;
+ reloc->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(reloc->map))
+ return PTR_ERR(reloc->map);
+
+ reloc->offset = res->start;
+ reloc->num_entries = num_entries;
+
+ reloc->val_bytes = regmap_get_val_bytes(reloc->map);
+ if (reloc->val_bytes < 0)
+ return -EINVAL;
+
+ ret = regmap_bulk_write(reloc->map, reloc->offset, reloc->entries,
+ reloc->num_entries *
+ sizeof(struct pil_reloc_entry) /
+ reloc->val_bytes);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&reloc_mutex);
+ _reloc = reloc;
+ mutex_unlock(&reloc_mutex);
+
+ return 0;
+}
+
+static int pil_reloc_remove(struct platform_device *pdev)
+{
+ mutex_lock(&reloc_mutex);
+ _reloc = NULL;
+ mutex_unlock(&reloc_mutex);
+
+ return 0;
+}
+
+static const struct of_device_id pil_reloc_of_match[] = {
+ { .compatible = "qcom,pil-reloc-info" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pil_reloc_of_match);
+
+static struct platform_driver pil_reloc_driver = {
+ .probe = pil_reloc_probe,
+ .remove = pil_reloc_remove,
+ .driver = {
+ .name = "qcom-pil-reloc-info",
+ .of_match_table = pil_reloc_of_match,
+ },
+};
+module_platform_driver(pil_reloc_driver);
+
+MODULE_DESCRIPTION("Qualcomm PIL relocation info");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_pil_info.h b/drivers/remoteproc/qcom_pil_info.h
new file mode 100644
index 000000000000..93aaaca8aed2
--- /dev/null
+++ b/drivers/remoteproc/qcom_pil_info.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __QCOM_PIL_INFO_H__
+#define __QCOM_PIL_INFO_H__
+
+int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size);
+bool qcom_pil_info_available(void);
+
+#endif
--
2.24.0

2020-02-11 00:54:36

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 3/8] remoteproc: qcom: Update IMEM PIL info on load

Update the PIL info region structure in IMEM with information about
where the firmware for various remoteprocs are loaded.

Signed-off-by: Bjorn Andersson <[email protected]>
---

Changes since v2:
- Wrapped a long line

drivers/remoteproc/Kconfig | 3 +++
drivers/remoteproc/qcom_q6v5_adsp.c | 19 ++++++++++++++++---
drivers/remoteproc/qcom_q6v5_mss.c | 6 ++++++
drivers/remoteproc/qcom_q6v5_pas.c | 18 +++++++++++++++---
drivers/remoteproc/qcom_wcnss.c | 17 ++++++++++++++---
5 files changed, 54 insertions(+), 9 deletions(-)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 20c8194e610e..7f4834ab06c2 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -129,6 +129,7 @@ config QCOM_Q6V5_MSS
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
+ select QCOM_PIL_INFO
select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
@@ -145,6 +146,7 @@ config QCOM_Q6V5_PAS
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
+ select QCOM_PIL_INFO
select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
@@ -193,6 +195,7 @@ config QCOM_WCNSS_PIL
depends on QCOM_SMEM
depends on QCOM_SYSMON || QCOM_SYSMON=n
select QCOM_MDT_LOADER
+ select QCOM_PIL_INFO
select QCOM_RPROC_COMMON
select QCOM_SCM
help
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index e953886b2eb7..19f784adf91c 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -26,6 +26,7 @@
#include <linux/soc/qcom/smem_state.h>

#include "qcom_common.h"
+#include "qcom_pil_info.h"
#include "qcom_q6v5.h"
#include "remoteproc_internal.h"

@@ -82,6 +83,7 @@ struct qcom_adsp {
unsigned int halt_lpass;

int crash_reason_smem;
+ const char *info_name;

struct completion start_done;
struct completion stop_done;
@@ -164,10 +166,17 @@ static int qcom_adsp_shutdown(struct qcom_adsp *adsp)
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+ int ret;
+
+ ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
+ adsp->mem_region, adsp->mem_phys,
+ adsp->mem_size, &adsp->mem_reloc);
+ if (ret)
+ return ret;

- return qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
- adsp->mem_region, adsp->mem_phys, adsp->mem_size,
- &adsp->mem_reloc);
+ qcom_pil_info_store(adsp->info_name, adsp->mem_reloc, adsp->mem_size);
+
+ return 0;
}

static int adsp_start(struct rproc *rproc)
@@ -413,6 +422,9 @@ static int adsp_probe(struct platform_device *pdev)
struct rproc *rproc;
int ret;

+ if (!qcom_pil_info_available())
+ return -EPROBE_DEFER;
+
desc = of_device_get_match_data(&pdev->dev);
if (!desc)
return -EINVAL;
@@ -427,6 +439,7 @@ static int adsp_probe(struct platform_device *pdev)
adsp = (struct qcom_adsp *)rproc->priv;
adsp->dev = &pdev->dev;
adsp->rproc = rproc;
+ adsp->info_name = desc->sysmon_name;
platform_set_drvdata(pdev, adsp);

ret = adsp_alloc_memory_region(adsp);
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index a1cc9cbe038f..66ed4600db78 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -28,6 +28,7 @@

#include "remoteproc_internal.h"
#include "qcom_common.h"
+#include "qcom_pil_info.h"
#include "qcom_q6v5.h"

#include <linux/qcom_scm.h>
@@ -1166,6 +1167,8 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
else if (ret < 0)
dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret);

+ qcom_pil_info_store("modem", mpss_reloc, qproc->mpss_size);
+
release_firmware:
release_firmware(fw);
out:
@@ -1555,6 +1558,9 @@ static int q6v5_probe(struct platform_device *pdev)
if (desc->need_mem_protection && !qcom_scm_is_available())
return -EPROBE_DEFER;

+ if (!qcom_pil_info_available())
+ return -EPROBE_DEFER;
+
mba_image = desc->hexagon_mba_image;
ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name",
0, &mba_image);
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index edf9d0e1a235..d20ce3c62256 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -25,6 +25,7 @@
#include <linux/soc/qcom/smem_state.h>

#include "qcom_common.h"
+#include "qcom_pil_info.h"
#include "qcom_q6v5.h"
#include "remoteproc_internal.h"

@@ -64,6 +65,7 @@ struct qcom_adsp {
int pas_id;
int crash_reason_smem;
bool has_aggre2_clk;
+ const char *info_name;

struct completion start_done;
struct completion stop_done;
@@ -117,11 +119,17 @@ static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+ int ret;
+
+ ret = qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
+ adsp->mem_region, adsp->mem_phys, adsp->mem_size,
+ &adsp->mem_reloc);
+ if (ret)
+ return ret;

- return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
- adsp->mem_region, adsp->mem_phys, adsp->mem_size,
- &adsp->mem_reloc);
+ qcom_pil_info_store(adsp->info_name, adsp->mem_reloc, adsp->mem_size);

+ return 0;
}

static int adsp_start(struct rproc *rproc)
@@ -376,6 +384,9 @@ static int adsp_probe(struct platform_device *pdev)
if (!qcom_scm_is_available())
return -EPROBE_DEFER;

+ if (!qcom_pil_info_available())
+ return -EPROBE_DEFER;
+
fw_name = desc->firmware_name;
ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
&fw_name);
@@ -396,6 +407,7 @@ static int adsp_probe(struct platform_device *pdev)
adsp->rproc = rproc;
adsp->pas_id = desc->pas_id;
adsp->has_aggre2_clk = desc->has_aggre2_clk;
+ adsp->info_name = desc->sysmon_name;
platform_set_drvdata(pdev, adsp);

ret = adsp_alloc_memory_region(adsp);
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index dc135754bb9c..2c1cefeacf97 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -27,6 +27,7 @@

#include "qcom_common.h"
#include "remoteproc_internal.h"
+#include "qcom_pil_info.h"
#include "qcom_wcnss.h"

#define WCNSS_CRASH_REASON_SMEM 422
@@ -145,10 +146,17 @@ void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss,
static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+ int ret;
+
+ ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
+ wcnss->mem_region, wcnss->mem_phys,
+ wcnss->mem_size, &wcnss->mem_reloc);
+ if (ret)
+ return ret;

- return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
- wcnss->mem_region, wcnss->mem_phys,
- wcnss->mem_size, &wcnss->mem_reloc);
+ qcom_pil_info_store("wcnss", wcnss->mem_reloc, wcnss->mem_size);
+
+ return 0;
}

static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
@@ -469,6 +477,9 @@ static int wcnss_probe(struct platform_device *pdev)
if (!qcom_scm_is_available())
return -EPROBE_DEFER;

+ if (!qcom_pil_info_available())
+ return -EPROBE_DEFER;
+
if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
return -ENXIO;
--
2.24.0

2020-02-13 16:01:10

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH v3 6/8] remoteproc: Introduce "panic" callback in ops


On 2/11/20 1:50 AM, Bjorn Andersson wrote:
> Introduce a "panic" function in the remoteproc ops table, to allow
> remoteproc instances to perform operations needed in order to aid in
> post mortem system debugging, such as flushing caches etc, when the
> kernel panics. The function can return a number of milliseconds needed
> by the remote to "settle" and the core will wait the longest returned
> duration before returning from the panic handler.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
>
> Changes since v2:
> - Replace per-rproc notifier callback with one generic
> - Move the mdelay() from the individual drivers to the core and sleep the
> longest returned duration. Drivers that doesn't need a delay can return 0.
> - Unregister the notifier on exit
>
> drivers/remoteproc/remoteproc_core.c | 46 ++++++++++++++++++++++++++++
> include/linux/remoteproc.h | 3 ++
> 2 files changed, 49 insertions(+)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 097f33e4f1f3..8b6932027d36 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -16,6 +16,7 @@
>
> #define pr_fmt(fmt) "%s: " fmt, __func__
>
> +#include <linux/delay.h>
> #include <linux/kernel.h>
> #include <linux/module.h>
> #include <linux/device.h>
> @@ -43,6 +44,7 @@
>
> static DEFINE_MUTEX(rproc_list_mutex);
> static LIST_HEAD(rproc_list);
> +static struct notifier_block rproc_panic_nb;
>
> typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
> void *, int offset, int avail);
> @@ -2216,10 +2218,53 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
> }
> EXPORT_SYMBOL(rproc_report_crash);
>
> +static int rproc_panic_handler(struct notifier_block *nb, unsigned long event,
> + void *ptr)
> +{
> + unsigned int longest = 0;
> + struct rproc *rproc;
> + unsigned int d;
> + int locked;
> +
> + locked = mutex_trylock(&rproc_list_mutex);
> + if (!locked) {
> + pr_err("Failed to acquire rproc list lock, won't call panic functions\n");
> + return NOTIFY_DONE;
> + }
As consequence the panic is not handled for all rproc instance if the mutex is locked.
it seems to me that the first solution with the delay side effect is more safety...

> +
> + list_for_each_entry(rproc, &rproc_list, node) {
> + if (!rproc->ops->panic || rproc->state != RPROC_RUNNING)
> + continue;
> +
> + d = rproc->ops->panic(rproc);
> + if (d > longest)
> + longest = d;
> + }
> +
> + mutex_unlock(&rproc_list_mutex);
> +
> + /* Delay panic for the longest requested duration */
> + mdelay(longest);
> +
> + return NOTIFY_DONE;
> +}
> +
> +static void __init rproc_init_panic(void)
> +{
> + rproc_panic_nb.notifier_call = rproc_panic_handler;
> + atomic_notifier_chain_register(&panic_notifier_list, &rproc_panic_nb);
> +}
> +
> +static void __exit rproc_exit_panic(void)
> +{
> + atomic_notifier_chain_unregister(&panic_notifier_list, &rproc_panic_nb);
> +}
> +
> static int __init remoteproc_init(void)
> {
> rproc_init_sysfs();
> rproc_init_debugfs();
> + rproc_init_panic();
>
> return 0;
> }
> @@ -2229,6 +2274,7 @@ static void __exit remoteproc_exit(void)
> {
> ida_destroy(&rproc_dev_index);
>
> + rproc_exit_panic();
> rproc_exit_debugfs();
> rproc_exit_sysfs();
> }
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 16ad66683ad0..14f05f26cbcd 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -369,6 +369,8 @@ enum rsc_handling_status {
> * expects to find it
> * @sanity_check: sanity check the fw image
> * @get_boot_addr: get boot address to entry point specified in firmware
> + * @panic: optional callback to react to system panic, core will delay
> + * panic at least the returned number of milliseconds
> */
> struct rproc_ops {
> int (*start)(struct rproc *rproc);
> @@ -383,6 +385,7 @@ struct rproc_ops {
> int (*load)(struct rproc *rproc, const struct firmware *fw);
> int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> + unsigned int (*panic)(struct rproc *rproc);
> };
>
> /**
>

2020-02-14 02:24:59

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 1/8] dt-bindings: remoteproc: Add Qualcomm PIL info binding

Quoting Bjorn Andersson (2020-02-10 16:50:52)
> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
> new file mode 100644
> index 000000000000..8386a4da6030
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
> @@ -0,0 +1,42 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/remoteproc/qcom,pil-info.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm peripheral image loader relocation info binding
> +
> +maintainers:
> + - Bjorn Andersson <[email protected]>
> +
> +description:
> + This document defines the binding for describing the Qualcomm peripheral

Maybe drop "This document defines the binding for describing".

> + image loader relocation memory region, in IMEM, which is used for post mortem
> + debugging of remoteprocs.
> +
> +properties:
> + compatible:
> + const: qcom,pil-reloc-info
> +
> + reg:
> + maxItems: 1
> +
> +required:
> + - compatible
> + - reg
> +
> +examples:
> + - |
> + imem@146bf000 {
> + compatible = "syscon", "simple-mfd";
> + reg = <0 0x146bf000 0 0x1000>;
> +
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + pil-reloc {

Should that be pil-reloc@94c?

> + compatible ="qcom,pil-reloc-info";
> + reg = <0x94c 200>;
> + };
> + };

2020-02-14 02:36:19

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 2/8] remoteproc: qcom: Introduce driver to store pil info in IMEM

Quoting Bjorn Andersson (2020-02-10 16:50:53)
> diff --git a/drivers/remoteproc/qcom_pil_info.c b/drivers/remoteproc/qcom_pil_info.c
> new file mode 100644
> index 000000000000..398aeb957f3c
> --- /dev/null
> +++ b/drivers/remoteproc/qcom_pil_info.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2019-2020 Linaro Ltd.
> + */
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +#define PIL_RELOC_NAME_LEN 8
> +
> +struct pil_reloc_entry {
> + char name[PIL_RELOC_NAME_LEN];
> + __le64 base;
> + __le32 size;
> +} __packed;

Does this need __packed? Isn't it naturally aligned?

> +
> +struct pil_reloc {
> + struct device *dev;
> + struct regmap *map;
> + size_t offset;
> + size_t num_entries;
> + int val_bytes;

unsigned int?

> +
> + struct pil_reloc_entry entries[];
> +};
> +
> +static struct pil_reloc *_reloc;

Can this be const? Or marked __read_mostly?

> +static DEFINE_MUTEX(reloc_mutex);
> +
> +/**
> + * qcom_pil_info_store() - store PIL information of image in IMEM
> + * @image: name of the image
> + * @base: base address of the loaded image
> + * @size: size of the loaded image
> + *
> + * Return: 0 on success, negative errno on failure
> + */
> +int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size)
> +{
> + struct pil_reloc_entry *entry;
> + int idx = -1;
> + int ret;
> + int i;
> +
> + mutex_lock(&reloc_mutex);
> + for (i = 0; i < _reloc->num_entries; i++) {
> + if (!_reloc->entries[i].name[0]) {
> + if (idx == -1)
> + idx = i;
> + continue;
> + }
> +
> + if (!strncmp(_reloc->entries[i].name, image, 8)) {
> + idx = i;
> + goto found;
> + }
> + }
> +
> + if (idx == -1) {

Maybe it would be better to use a pointer and set it to NULL when it
isn't found. Then do some pointer math on the 'entry' to find the
address to regmap_bulk_write() below.

> + dev_warn(_reloc->dev, "insufficient PIL info slots\n");
> + ret = -ENOMEM;
> + goto unlock;
> + }
> +
> +found:
> + entry = &_reloc->entries[idx];
> + strscpy(entry->name, image, ARRAY_SIZE(entry->name));
> + entry->base = base;
> + entry->size = size;
> +
> + ret = regmap_bulk_write(_reloc->map,
> + _reloc->offset + idx * sizeof(*entry),
> + entry, sizeof(*entry) / _reloc->val_bytes);
> +unlock:
> + mutex_unlock(&reloc_mutex);

Does the mutex need to be held until here? Why can't we release it once
we find the entry?

> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(qcom_pil_info_store);
> +
> +/**
> + * qcom_pil_info_available() - query if the pil info is probed
> + *
> + * Return: boolean indicating if the pil info device is probed
> + */
> +bool qcom_pil_info_available(void)
> +{
> + return !!_reloc;
> +}
> +EXPORT_SYMBOL_GPL(qcom_pil_info_available);
> +
> +static int pil_reloc_probe(struct platform_device *pdev)
> +{
> + unsigned int num_entries;
> + struct pil_reloc *reloc;
> + struct resource *res;
> + int ret;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res)
> + return -EINVAL;
> +
> + num_entries = resource_size(res) / sizeof(struct pil_reloc_entry);
> +
> + reloc = devm_kzalloc(&pdev->dev,
> + struct_size(reloc, entries, num_entries),
> + GFP_KERNEL);
> + if (!reloc)
> + return -ENOMEM;
> +
> + reloc->dev = &pdev->dev;
> + reloc->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
> + if (IS_ERR(reloc->map))
> + return PTR_ERR(reloc->map);
> +
> + reloc->offset = res->start;
> + reloc->num_entries = num_entries;
> +
> + reloc->val_bytes = regmap_get_val_bytes(reloc->map);
> + if (reloc->val_bytes < 0)
> + return -EINVAL;
> +
> + ret = regmap_bulk_write(reloc->map, reloc->offset, reloc->entries,
> + reloc->num_entries *
> + sizeof(struct pil_reloc_entry) /
> + reloc->val_bytes);
> + if (ret < 0)
> + return ret;
> +
> + mutex_lock(&reloc_mutex);
> + _reloc = reloc;
> + mutex_unlock(&reloc_mutex);

Ah ok, I see that mutex is protecting the pointer used for everything.
Ignore the comment above. But also, why not have every remoteproc device
point at some imem and then search through the imem for the name? Then
we don't need this driver or a lock that synchronizes these things.
Ideally we could dedicate a place in imem for each remoteproc and not
even have to search it for the string to update. Is that possible? Then
it becomes even simpler because the DT binding can point directly at the
address to write. It's not like the various images are changing that
much to the point where this location in imem is actually changing,
right?

> +
> + return 0;
> +}

2020-02-14 02:37:24

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 4/8] arm64: dts: qcom: qcs404: Add IMEM and PIL info region

Quoting Bjorn Andersson (2020-02-10 16:50:55)
> diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> index 4ee1e3d5f123..f539293b875c 100644
> --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
> +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> @@ -997,6 +997,19 @@ blsp2_spi0: spi@7af5000 {
> status = "disabled";
> };
>
> + imem@8600000 {
> + compatible = "syscon", "simple-mfd";
> + reg = <0x08600000 0x1000>;
> +
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + pil-reloc@94c {
> + compatible ="qcom,pil-reloc-info";
> + reg = <0x94c 200>;

Is it 200 in decimal? It looks weird that this is basically the only
thing that isn't in hexadecimal.

> + };
> + };
> +

2020-02-14 02:41:35

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 6/8] remoteproc: Introduce "panic" callback in ops

Quoting Bjorn Andersson (2020-02-10 16:50:57)
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 097f33e4f1f3..8b6932027d36 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -2216,10 +2218,53 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
> }
> EXPORT_SYMBOL(rproc_report_crash);
>
> +static int rproc_panic_handler(struct notifier_block *nb, unsigned long event,
> + void *ptr)
> +{
> + unsigned int longest = 0;
> + struct rproc *rproc;
> + unsigned int d;
> + int locked;
> +
> + locked = mutex_trylock(&rproc_list_mutex);
> + if (!locked) {
> + pr_err("Failed to acquire rproc list lock, won't call panic functions\n");
> + return NOTIFY_DONE;
> + }
> +
> + list_for_each_entry(rproc, &rproc_list, node) {
> + if (!rproc->ops->panic || rproc->state != RPROC_RUNNING)
> + continue;
> +
> + d = rproc->ops->panic(rproc);
> + if (d > longest)
> + longest = d;

Could be

d = max(longest, d);

> + }
> +
> + mutex_unlock(&rproc_list_mutex);
> +
> + /* Delay panic for the longest requested duration */
> + mdelay(longest);

Is this to flush caches? Maybe indicate that in the comment.

> +
> + return NOTIFY_DONE;
> +}
> +
> +static void __init rproc_init_panic(void)
> +{
> + rproc_panic_nb.notifier_call = rproc_panic_handler;
> + atomic_notifier_chain_register(&panic_notifier_list, &rproc_panic_nb);

This is an atomic notifier, but the notifier function takes a mutex,
which sleeps. It should use spinlocks, and never sleep, given that panic
can be called from anywhere.

> +}
> +
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 16ad66683ad0..14f05f26cbcd 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -369,6 +369,8 @@ enum rsc_handling_status {
> * expects to find it
> * @sanity_check: sanity check the fw image
> * @get_boot_addr: get boot address to entry point specified in firmware
> + * @panic: optional callback to react to system panic, core will delay
> + * panic at least the returned number of milliseconds
> */
> struct rproc_ops {
> int (*start)(struct rproc *rproc);
> @@ -383,6 +385,7 @@ struct rproc_ops {
> int (*load)(struct rproc *rproc, const struct firmware *fw);
> int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> + unsigned int (*panic)(struct rproc *rproc);

Maybe should be unsigned long to match other "timeouts" in the kernel.

2020-02-14 02:45:06

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 8/8] remoteproc: qcom: Introduce panic handler for PAS and ADSP

Quoting Bjorn Andersson (2020-02-10 16:50:59)
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index 19f784adf91c..822881534d37 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -291,12 +291,20 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> return adsp->mem_region + offset;
> }
>
> +static unsigned int adsp_panic(struct rproc *rproc)
> +{
> + struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;

We don't need to cast from void. Please drop the cast.

> +
> + return qcom_q6v5_panic(&adsp->q6v5);
> +}
> +
> static const struct rproc_ops adsp_ops = {
> .start = adsp_start,
> .stop = adsp_stop,
> .da_to_va = adsp_da_to_va,
> .parse_fw = qcom_register_dump_segments,
> .load = adsp_load,
> + .panic = adsp_panic,
> };
>
> static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids)
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index d20ce3c62256..ac38624fb14d 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -242,12 +242,20 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> return adsp->mem_region + offset;
> }
>
> +static unsigned int adsp_panic(struct rproc *rproc)
> +{
> + struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;

Same.

> +
> + return qcom_q6v5_panic(&adsp->q6v5);
> +}

2020-02-14 04:39:24

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 6/8] remoteproc: Introduce "panic" callback in ops

On Thu 13 Feb 18:41 PST 2020, Stephen Boyd wrote:

> Quoting Bjorn Andersson (2020-02-10 16:50:57)
> > diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> > index 097f33e4f1f3..8b6932027d36 100644
> > --- a/drivers/remoteproc/remoteproc_core.c
> > +++ b/drivers/remoteproc/remoteproc_core.c
> > @@ -2216,10 +2218,53 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
> > }
> > EXPORT_SYMBOL(rproc_report_crash);
> >
> > +static int rproc_panic_handler(struct notifier_block *nb, unsigned long event,
> > + void *ptr)
> > +{
> > + unsigned int longest = 0;
> > + struct rproc *rproc;
> > + unsigned int d;
> > + int locked;
> > +
> > + locked = mutex_trylock(&rproc_list_mutex);
> > + if (!locked) {
> > + pr_err("Failed to acquire rproc list lock, won't call panic functions\n");
> > + return NOTIFY_DONE;
> > + }
> > +
> > + list_for_each_entry(rproc, &rproc_list, node) {
> > + if (!rproc->ops->panic || rproc->state != RPROC_RUNNING)
> > + continue;
> > +
> > + d = rproc->ops->panic(rproc);
> > + if (d > longest)
> > + longest = d;
>
> Could be
>
> d = max(longest, d);
>

I like this better and now I have an excuse to change to it.

> > + }
> > +
> > + mutex_unlock(&rproc_list_mutex);
> > +
> > + /* Delay panic for the longest requested duration */
> > + mdelay(longest);
>
> Is this to flush caches? Maybe indicate that in the comment.
>

Here, in the core, it's for whatever the individual drivers might need
it for, but "flushing caches" is likely the main purpose.

That said, the Qualcomm implementation is, as you can see, to issue a
generic "stop request", so flushing caches will not be the only thing
that happens.

> > +
> > + return NOTIFY_DONE;
> > +}
> > +
> > +static void __init rproc_init_panic(void)
> > +{
> > + rproc_panic_nb.notifier_call = rproc_panic_handler;
> > + atomic_notifier_chain_register(&panic_notifier_list, &rproc_panic_nb);
>
> This is an atomic notifier, but the notifier function takes a mutex,
> which sleeps. It should use spinlocks, and never sleep, given that panic
> can be called from anywhere.
>

Given that we're only trylocking I was expecting there not to be a
sleep. But if that's the case I'll have to revisit this.

If I rework rproc_get_by_phandle() slightly I should be able to rely on
rcu instead of the mutex for the two readers, which would also resolve
Arnaud's concern regarding the possibility of a panic while updating the
list will cause the panic handling to be skipped.

> > +}
> > +
> > diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> > index 16ad66683ad0..14f05f26cbcd 100644
> > --- a/include/linux/remoteproc.h
> > +++ b/include/linux/remoteproc.h
> > @@ -369,6 +369,8 @@ enum rsc_handling_status {
> > * expects to find it
> > * @sanity_check: sanity check the fw image
> > * @get_boot_addr: get boot address to entry point specified in firmware
> > + * @panic: optional callback to react to system panic, core will delay
> > + * panic at least the returned number of milliseconds
> > */
> > struct rproc_ops {
> > int (*start)(struct rproc *rproc);
> > @@ -383,6 +385,7 @@ struct rproc_ops {
> > int (*load)(struct rproc *rproc, const struct firmware *fw);
> > int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> > u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> > + unsigned int (*panic)(struct rproc *rproc);
>
> Maybe should be unsigned long to match other "timeouts" in the kernel.

Sounds good.

Thanks,
Bjorn

2020-02-14 04:42:29

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 4/8] arm64: dts: qcom: qcs404: Add IMEM and PIL info region

On Thu 13 Feb 18:37 PST 2020, Stephen Boyd wrote:

> Quoting Bjorn Andersson (2020-02-10 16:50:55)
> > diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> > index 4ee1e3d5f123..f539293b875c 100644
> > --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> > @@ -997,6 +997,19 @@ blsp2_spi0: spi@7af5000 {
> > status = "disabled";
> > };
> >
> > + imem@8600000 {
> > + compatible = "syscon", "simple-mfd";
> > + reg = <0x08600000 0x1000>;
> > +
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > +
> > + pil-reloc@94c {
> > + compatible ="qcom,pil-reloc-info";
> > + reg = <0x94c 200>;
>
> Is it 200 in decimal? It looks weird that this is basically the only
> thing that isn't in hexadecimal.
>

Yes it is and the size was documented as such... But you're probably not
the last one who will spend cycles wondering if I forgot the 0x.

Regards,
Bjorn

> > + };
> > + };
> > +

2020-02-14 04:58:36

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 2/8] remoteproc: qcom: Introduce driver to store pil info in IMEM

On Thu 13 Feb 18:35 PST 2020, Stephen Boyd wrote:
> Quoting Bjorn Andersson (2020-02-10 16:50:53)
> > diff --git a/drivers/remoteproc/qcom_pil_info.c b/drivers/remoteproc/qcom_pil_info.c
[..]
> > + mutex_lock(&reloc_mutex);
> > + _reloc = reloc;
> > + mutex_unlock(&reloc_mutex);
>
> Ah ok, I see that mutex is protecting the pointer used for everything.
> Ignore the comment above. But also, why not have every remoteproc device
> point at some imem and then search through the imem for the name? Then
> we don't need this driver or a lock that synchronizes these things.
> Ideally we could dedicate a place in imem for each remoteproc and not
> even have to search it for the string to update. Is that possible? Then
> it becomes even simpler because the DT binding can point directly at the
> address to write. It's not like the various images are changing that
> much to the point where this location in imem is actually changing,
> right?
>

I will check to see if these entries needs to be packed in the beginning
of the array, otherwise this sounds like a good idea to simplify things.

Regards,
Bjorn

2020-02-14 04:59:53

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 1/8] dt-bindings: remoteproc: Add Qualcomm PIL info binding

On Thu 13 Feb 18:24 PST 2020, Stephen Boyd wrote:

> Quoting Bjorn Andersson (2020-02-10 16:50:52)
> > diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
> > new file mode 100644
> > index 000000000000..8386a4da6030
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
> > @@ -0,0 +1,42 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/remoteproc/qcom,pil-info.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Qualcomm peripheral image loader relocation info binding
> > +
> > +maintainers:
> > + - Bjorn Andersson <[email protected]>
> > +
> > +description:
> > + This document defines the binding for describing the Qualcomm peripheral
>
> Maybe drop "This document defines the binding for describing".
>

Sounds reasonable.

> > + image loader relocation memory region, in IMEM, which is used for post mortem
> > + debugging of remoteprocs.
> > +
> > +properties:
> > + compatible:
> > + const: qcom,pil-reloc-info
> > +
> > + reg:
> > + maxItems: 1
> > +
> > +required:
> > + - compatible
> > + - reg
> > +
> > +examples:
> > + - |
> > + imem@146bf000 {
> > + compatible = "syscon", "simple-mfd";
> > + reg = <0 0x146bf000 0 0x1000>;
> > +
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > +
> > + pil-reloc {
>
> Should that be pil-reloc@94c?
>

Yes it should.

Thanks,
Bjorn

> > + compatible ="qcom,pil-reloc-info";
> > + reg = <0x94c 200>;
> > + };
> > + };

2020-02-20 17:59:37

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 1/8] dt-bindings: remoteproc: Add Qualcomm PIL info binding

On Mon, Feb 10, 2020 at 04:50:52PM -0800, Bjorn Andersson wrote:
> Add a devicetree binding for the Qualcomm periperal image loader

s/periperal/peripheral

> relocation info region found in the IMEM.

s/info/information

>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
>
> Changes since v2:
> - Replaced offset with reg to describe the region of IMEM used for the entries
>
> .../bindings/remoteproc/qcom,pil-info.yaml | 42 +++++++++++++++++++
> 1 file changed, 42 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
> new file mode 100644
> index 000000000000..8386a4da6030
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
> @@ -0,0 +1,42 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/remoteproc/qcom,pil-info.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm peripheral image loader relocation info binding
> +
> +maintainers:
> + - Bjorn Andersson <[email protected]>
> +
> +description:
> + This document defines the binding for describing the Qualcomm peripheral
> + image loader relocation memory region, in IMEM, which is used for post mortem
> + debugging of remoteprocs.
> +
> +properties:
> + compatible:
> + const: qcom,pil-reloc-info
> +
> + reg:
> + maxItems: 1
> +
> +required:
> + - compatible
> + - reg
> +
> +examples:
> + - |
> + imem@146bf000 {
> + compatible = "syscon", "simple-mfd";
> + reg = <0 0x146bf000 0 0x1000>;
> +
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + pil-reloc {
> + compatible ="qcom,pil-reloc-info";

s/="/= "

> + reg = <0x94c 200>;
> + };
> + };
> +...
> --
> 2.24.0
>

2020-02-20 19:02:14

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 2/8] remoteproc: qcom: Introduce driver to store pil info in IMEM

On Mon, Feb 10, 2020 at 04:50:53PM -0800, Bjorn Andersson wrote:
> A region in IMEM is used to communicate load addresses of remoteproc to
> post mortem debug tools. Implement a driver that can be used to store
> this information in order to enable these tools to process collected
> ramdumps.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
>
> Changes since v2:
> - Sorted includes
> - Replace use of stracpy (still not landed upstream)
> - Fixed error handling in probe
> - Return error from store, to allow clients to decide action
> - Replace hard coded size with value read from reg property
>
> drivers/remoteproc/Kconfig | 3 +
> drivers/remoteproc/Makefile | 1 +
> drivers/remoteproc/qcom_pil_info.c | 168 +++++++++++++++++++++++++++++
> drivers/remoteproc/qcom_pil_info.h | 8 ++
> 4 files changed, 180 insertions(+)
> create mode 100644 drivers/remoteproc/qcom_pil_info.c
> create mode 100644 drivers/remoteproc/qcom_pil_info.h
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index de3862c15fcc..20c8194e610e 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -95,6 +95,9 @@ config KEYSTONE_REMOTEPROC
> It's safe to say N here if you're not interested in the Keystone
> DSPs or just want to use a bare minimum kernel.
>
> +config QCOM_PIL_INFO
> + tristate
> +
> config QCOM_RPROC_COMMON
> tristate
>
> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> index e30a1b15fbac..2ab32bd41b44 100644
> --- a/drivers/remoteproc/Makefile
> +++ b/drivers/remoteproc/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
> obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
> obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
> obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o
> +obj-$(CONFIG_QCOM_PIL_INFO) += qcom_pil_info.o
> obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o
> obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o
> obj-$(CONFIG_QCOM_Q6V5_ADSP) += qcom_q6v5_adsp.o
> diff --git a/drivers/remoteproc/qcom_pil_info.c b/drivers/remoteproc/qcom_pil_info.c
> new file mode 100644
> index 000000000000..398aeb957f3c
> --- /dev/null
> +++ b/drivers/remoteproc/qcom_pil_info.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2019-2020 Linaro Ltd.
> + */
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +#define PIL_RELOC_NAME_LEN 8
> +
> +struct pil_reloc_entry {
> + char name[PIL_RELOC_NAME_LEN];
> + __le64 base;
> + __le32 size;
> +} __packed;
> +
> +struct pil_reloc {
> + struct device *dev;
> + struct regmap *map;
> + size_t offset;
> + size_t num_entries;
> + int val_bytes;
> +
> + struct pil_reloc_entry entries[];
> +};
> +
> +static struct pil_reloc *_reloc;
> +static DEFINE_MUTEX(reloc_mutex);
> +
> +/**
> + * qcom_pil_info_store() - store PIL information of image in IMEM
> + * @image: name of the image
> + * @base: base address of the loaded image
> + * @size: size of the loaded image
> + *
> + * Return: 0 on success, negative errno on failure
> + */
> +int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size)
> +{
> + struct pil_reloc_entry *entry;
> + int idx = -1;
> + int ret;
> + int i;
> +
> + mutex_lock(&reloc_mutex);
> + for (i = 0; i < _reloc->num_entries; i++) {
> + if (!_reloc->entries[i].name[0]) {
> + if (idx == -1)
> + idx = i;
> + continue;
> + }
> +
> + if (!strncmp(_reloc->entries[i].name, image, 8)) {

s/8/PIL_RELOC_NAME_LEN

> + idx = i;
> + goto found;
> + }
> + }
> +
> + if (idx == -1) {
> + dev_warn(_reloc->dev, "insufficient PIL info slots\n");
> + ret = -ENOMEM;
> + goto unlock;
> + }
> +
> +found:
> + entry = &_reloc->entries[idx];
> + strscpy(entry->name, image, ARRAY_SIZE(entry->name));
> + entry->base = base;
> + entry->size = size;
> +
> + ret = regmap_bulk_write(_reloc->map,
> + _reloc->offset + idx * sizeof(*entry),
> + entry, sizeof(*entry) / _reloc->val_bytes);
> +unlock:
> + mutex_unlock(&reloc_mutex);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(qcom_pil_info_store);
> +
> +/**
> + * qcom_pil_info_available() - query if the pil info is probed
> + *
> + * Return: boolean indicating if the pil info device is probed
> + */
> +bool qcom_pil_info_available(void)
> +{
> + return !!_reloc;
> +}
> +EXPORT_SYMBOL_GPL(qcom_pil_info_available);
> +
> +static int pil_reloc_probe(struct platform_device *pdev)
> +{
> + unsigned int num_entries;
> + struct pil_reloc *reloc;
> + struct resource *res;
> + int ret;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res)
> + return -EINVAL;
> +
> + num_entries = resource_size(res) / sizeof(struct pil_reloc_entry);
> +
> + reloc = devm_kzalloc(&pdev->dev,
> + struct_size(reloc, entries, num_entries),
> + GFP_KERNEL);
> + if (!reloc)
> + return -ENOMEM;
> +
> + reloc->dev = &pdev->dev;
> + reloc->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
> + if (IS_ERR(reloc->map))
> + return PTR_ERR(reloc->map);
> +
> + reloc->offset = res->start;
> + reloc->num_entries = num_entries;
> +
> + reloc->val_bytes = regmap_get_val_bytes(reloc->map);
> + if (reloc->val_bytes < 0)
> + return -EINVAL;
> +
> + ret = regmap_bulk_write(reloc->map, reloc->offset, reloc->entries,
> + reloc->num_entries *
> + sizeof(struct pil_reloc_entry) /
> + reloc->val_bytes);
> + if (ret < 0)
> + return ret;
> +
> + mutex_lock(&reloc_mutex);
> + _reloc = reloc;
> + mutex_unlock(&reloc_mutex);
> +
> + return 0;
> +}
> +
> +static int pil_reloc_remove(struct platform_device *pdev)
> +{
> + mutex_lock(&reloc_mutex);
> + _reloc = NULL;
> + mutex_unlock(&reloc_mutex);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id pil_reloc_of_match[] = {
> + { .compatible = "qcom,pil-reloc-info" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, pil_reloc_of_match);
> +
> +static struct platform_driver pil_reloc_driver = {
> + .probe = pil_reloc_probe,
> + .remove = pil_reloc_remove,
> + .driver = {
> + .name = "qcom-pil-reloc-info",
> + .of_match_table = pil_reloc_of_match,
> + },
> +};
> +module_platform_driver(pil_reloc_driver);
> +
> +MODULE_DESCRIPTION("Qualcomm PIL relocation info");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/remoteproc/qcom_pil_info.h b/drivers/remoteproc/qcom_pil_info.h
> new file mode 100644
> index 000000000000..93aaaca8aed2
> --- /dev/null
> +++ b/drivers/remoteproc/qcom_pil_info.h
> @@ -0,0 +1,8 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __QCOM_PIL_INFO_H__
> +#define __QCOM_PIL_INFO_H__
> +
> +int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size);
> +bool qcom_pil_info_available(void);
> +
> +#endif
> --
> 2.24.0
>

2020-02-20 20:43:27

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 3/8] remoteproc: qcom: Update IMEM PIL info on load

On Mon, Feb 10, 2020 at 04:50:54PM -0800, Bjorn Andersson wrote:
> Update the PIL info region structure in IMEM with information about
> where the firmware for various remoteprocs are loaded.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
>
> Changes since v2:
> - Wrapped a long line
>
> drivers/remoteproc/Kconfig | 3 +++
> drivers/remoteproc/qcom_q6v5_adsp.c | 19 ++++++++++++++++---
> drivers/remoteproc/qcom_q6v5_mss.c | 6 ++++++
> drivers/remoteproc/qcom_q6v5_pas.c | 18 +++++++++++++++---
> drivers/remoteproc/qcom_wcnss.c | 17 ++++++++++++++---
> 5 files changed, 54 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 20c8194e610e..7f4834ab06c2 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -129,6 +129,7 @@ config QCOM_Q6V5_MSS
> depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
> depends on QCOM_SYSMON || QCOM_SYSMON=n
> select MFD_SYSCON
> + select QCOM_PIL_INFO
> select QCOM_MDT_LOADER
> select QCOM_Q6V5_COMMON
> select QCOM_RPROC_COMMON
> @@ -145,6 +146,7 @@ config QCOM_Q6V5_PAS
> depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
> depends on QCOM_SYSMON || QCOM_SYSMON=n
> select MFD_SYSCON
> + select QCOM_PIL_INFO
> select QCOM_MDT_LOADER
> select QCOM_Q6V5_COMMON
> select QCOM_RPROC_COMMON
> @@ -193,6 +195,7 @@ config QCOM_WCNSS_PIL
> depends on QCOM_SMEM
> depends on QCOM_SYSMON || QCOM_SYSMON=n
> select QCOM_MDT_LOADER
> + select QCOM_PIL_INFO
> select QCOM_RPROC_COMMON
> select QCOM_SCM
> help
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index e953886b2eb7..19f784adf91c 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -26,6 +26,7 @@
> #include <linux/soc/qcom/smem_state.h>
>
> #include "qcom_common.h"
> +#include "qcom_pil_info.h"
> #include "qcom_q6v5.h"
> #include "remoteproc_internal.h"
>
> @@ -82,6 +83,7 @@ struct qcom_adsp {
> unsigned int halt_lpass;
>
> int crash_reason_smem;
> + const char *info_name;
>
> struct completion start_done;
> struct completion stop_done;
> @@ -164,10 +166,17 @@ static int qcom_adsp_shutdown(struct qcom_adsp *adsp)
> static int adsp_load(struct rproc *rproc, const struct firmware *fw)
> {
> struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> + int ret;
> +
> + ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
> + adsp->mem_region, adsp->mem_phys,
> + adsp->mem_size, &adsp->mem_reloc);
> + if (ret)
> + return ret;
>
> - return qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
> - adsp->mem_region, adsp->mem_phys, adsp->mem_size,
> - &adsp->mem_reloc);
> + qcom_pil_info_store(adsp->info_name, adsp->mem_reloc, adsp->mem_size);

It is entirely up to you to decide to add a comment that explains why you
opted not to handle the return. But can already see patches piling
up on the mailing list to "fix" the problem.

The same applies to the other hunks.

> +
> + return 0;
> }
>
> static int adsp_start(struct rproc *rproc)
> @@ -413,6 +422,9 @@ static int adsp_probe(struct platform_device *pdev)
> struct rproc *rproc;
> int ret;
>
> + if (!qcom_pil_info_available())
> + return -EPROBE_DEFER;
> +
> desc = of_device_get_match_data(&pdev->dev);
> if (!desc)
> return -EINVAL;
> @@ -427,6 +439,7 @@ static int adsp_probe(struct platform_device *pdev)
> adsp = (struct qcom_adsp *)rproc->priv;
> adsp->dev = &pdev->dev;
> adsp->rproc = rproc;
> + adsp->info_name = desc->sysmon_name;
> platform_set_drvdata(pdev, adsp);
>
> ret = adsp_alloc_memory_region(adsp);
> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
> index a1cc9cbe038f..66ed4600db78 100644
> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> @@ -28,6 +28,7 @@
>
> #include "remoteproc_internal.h"
> #include "qcom_common.h"
> +#include "qcom_pil_info.h"
> #include "qcom_q6v5.h"
>
> #include <linux/qcom_scm.h>
> @@ -1166,6 +1167,8 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
> else if (ret < 0)
> dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret);
>
> + qcom_pil_info_store("modem", mpss_reloc, qproc->mpss_size);
> +
> release_firmware:
> release_firmware(fw);
> out:
> @@ -1555,6 +1558,9 @@ static int q6v5_probe(struct platform_device *pdev)
> if (desc->need_mem_protection && !qcom_scm_is_available())
> return -EPROBE_DEFER;
>
> + if (!qcom_pil_info_available())
> + return -EPROBE_DEFER;
> +
> mba_image = desc->hexagon_mba_image;
> ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name",
> 0, &mba_image);
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index edf9d0e1a235..d20ce3c62256 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -25,6 +25,7 @@
> #include <linux/soc/qcom/smem_state.h>
>
> #include "qcom_common.h"
> +#include "qcom_pil_info.h"
> #include "qcom_q6v5.h"
> #include "remoteproc_internal.h"
>
> @@ -64,6 +65,7 @@ struct qcom_adsp {
> int pas_id;
> int crash_reason_smem;
> bool has_aggre2_clk;
> + const char *info_name;
>
> struct completion start_done;
> struct completion stop_done;
> @@ -117,11 +119,17 @@ static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
> static int adsp_load(struct rproc *rproc, const struct firmware *fw)
> {
> struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> + int ret;
> +
> + ret = qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
> + adsp->mem_region, adsp->mem_phys, adsp->mem_size,
> + &adsp->mem_reloc);
> + if (ret)
> + return ret;
>
> - return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
> - adsp->mem_region, adsp->mem_phys, adsp->mem_size,
> - &adsp->mem_reloc);
> + qcom_pil_info_store(adsp->info_name, adsp->mem_reloc, adsp->mem_size);
>
> + return 0;
> }
>
> static int adsp_start(struct rproc *rproc)
> @@ -376,6 +384,9 @@ static int adsp_probe(struct platform_device *pdev)
> if (!qcom_scm_is_available())
> return -EPROBE_DEFER;
>
> + if (!qcom_pil_info_available())
> + return -EPROBE_DEFER;
> +
> fw_name = desc->firmware_name;
> ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
> &fw_name);
> @@ -396,6 +407,7 @@ static int adsp_probe(struct platform_device *pdev)
> adsp->rproc = rproc;
> adsp->pas_id = desc->pas_id;
> adsp->has_aggre2_clk = desc->has_aggre2_clk;
> + adsp->info_name = desc->sysmon_name;
> platform_set_drvdata(pdev, adsp);
>
> ret = adsp_alloc_memory_region(adsp);
> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> index dc135754bb9c..2c1cefeacf97 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -27,6 +27,7 @@
>
> #include "qcom_common.h"
> #include "remoteproc_internal.h"
> +#include "qcom_pil_info.h"
> #include "qcom_wcnss.h"
>
> #define WCNSS_CRASH_REASON_SMEM 422
> @@ -145,10 +146,17 @@ void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss,
> static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
> {
> struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
> + int ret;
> +
> + ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
> + wcnss->mem_region, wcnss->mem_phys,
> + wcnss->mem_size, &wcnss->mem_reloc);
> + if (ret)
> + return ret;
>
> - return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
> - wcnss->mem_region, wcnss->mem_phys,
> - wcnss->mem_size, &wcnss->mem_reloc);
> + qcom_pil_info_store("wcnss", wcnss->mem_reloc, wcnss->mem_size);
> +
> + return 0;
> }
>
> static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
> @@ -469,6 +477,9 @@ static int wcnss_probe(struct platform_device *pdev)
> if (!qcom_scm_is_available())
> return -EPROBE_DEFER;
>
> + if (!qcom_pil_info_available())
> + return -EPROBE_DEFER;
> +
> if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
> dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
> return -ENXIO;
> --
> 2.24.0
>

2020-02-20 20:48:33

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 4/8] arm64: dts: qcom: qcs404: Add IMEM and PIL info region

On Mon, Feb 10, 2020 at 04:50:55PM -0800, Bjorn Andersson wrote:
> Add a simple-mfd representing IMEM on QCS404 and define the PIL
> relocation info region, so that post mortem tools will be able to locate
> the loaded remoteprocs.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
>
> Changes since v2:
> - Replace offset with reg
>
> arch/arm64/boot/dts/qcom/qcs404.dtsi | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> index 4ee1e3d5f123..f539293b875c 100644
> --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
> +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
> @@ -997,6 +997,19 @@ blsp2_spi0: spi@7af5000 {
> status = "disabled";
> };
>
> + imem@8600000 {
> + compatible = "syscon", "simple-mfd";
> + reg = <0x08600000 0x1000>;
> +
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + pil-reloc@94c {
> + compatible ="qcom,pil-reloc-info";

s/="/= "

> + reg = <0x94c 200>;
> + };
> + };
> +
> intc: interrupt-controller@b000000 {
> compatible = "qcom,msm-qgic2";
> interrupt-controller;
> --
> 2.24.0
>

2020-02-20 20:48:46

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 5/8] arm64: dts: qcom: sdm845: Add IMEM and PIL info region

On Mon, Feb 10, 2020 at 04:50:56PM -0800, Bjorn Andersson wrote:
> Add a simple-mfd representing IMEM on SDM845 and define the PIL
> relocation info region, so that post mortem tools will be able to locate
> the loaded remoteprocs.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
>
> Changes since v2:
> - Replace offset with reg
>
> arch/arm64/boot/dts/qcom/sdm845.dtsi | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> index d42302b8889b..3443d989976c 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> @@ -3018,6 +3018,19 @@ spmi_bus: spmi@c440000 {
> cell-index = <0>;
> };
>
> + imem@146bf000 {
> + compatible = "syscon", "simple-mfd";
> + reg = <0 0x146bf000 0 0x1000>;
> +
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + pil-reloc@94c {
> + compatible ="qcom,pil-reloc-info";

s/="/= "

> + reg = <0x94c 200>;
> + };
> + };
> +
> apps_smmu: iommu@15000000 {
> compatible = "qcom,sdm845-smmu-500", "arm,mmu-500";
> reg = <0 0x15000000 0 0x80000>;
> --
> 2.24.0
>