This patchset adds support for the mpss found in the QDU1000 and QRU1000
SoCs.
The mpss boot process now supports late attach for an already running
mpss. For this, it uses an RMB register space to perform a handshake
with the mpss for the late attach process. This is implemented in the
patches below. The patches also address issues with split binary
detection to support loading of split binaries more robustly.
Changes from v1:
* Dropped changes to aoss-qmp
* Renamed mpss pas bindings
* Updated commit msg on mdt loader to be more descriptive
* Fixed syntax errors in bindings
* Updated firmware name in bindings
Gokul Krishna Krishnakumar (1):
soc: qcom: mdt_loader: Enhance split binary detection
Melody Olvera (6):
dt-bindings: firmware: qcom,scm: Update QDU1000/QRU1000 compatible
dt-bindings: soc: qcom: aoss: Document QDU1000/QRU1000 compatible
dt-bindings: remoteproc: mpss: Document QDU1000/QRU1000 mpss devices
remoteproc: qcom: q6v5: Add support for q6 rmb registers
remoteproc: qcom_q6v5_pas: Add support to attach a DSP
remoteproc: qcom_q6v5_pas: Add QDU1000/QRU1000 mpss compatible & data
.../bindings/firmware/qcom,scm.yaml | 1 +
.../remoteproc/qcom,qdu1000-mpss-pas.yaml | 130 ++++++++++++++++++
.../bindings/soc/qcom/qcom,aoss-qmp.yaml | 1 +
drivers/remoteproc/qcom_q6v5.c | 9 ++
drivers/remoteproc/qcom_q6v5.h | 8 ++
drivers/remoteproc/qcom_q6v5_pas.c | 125 ++++++++++++++++-
drivers/soc/qcom/mdt_loader.c | 64 +++++----
7 files changed, 308 insertions(+), 30 deletions(-)
create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
base-commit: dc837c1a5137a8cf2e9432c1891392b6a66f4d8d
--
2.25.1
When attaching a running Q6, the remoteproc driver needs a way
to communicate with the Q6 using rmb registers, so allow the
rmb register to be gotten from the device tree if present.
Signed-off-by: Melody Olvera <[email protected]>
---
drivers/remoteproc/qcom_q6v5.c | 9 +++++++++
drivers/remoteproc/qcom_q6v5.h | 8 ++++++++
2 files changed, 17 insertions(+)
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 192c7aa0e39e..e8c6be70ebfd 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -254,6 +254,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
void (*handover)(struct qcom_q6v5 *q6v5))
{
int ret;
+ struct resource *res;
q6v5->rproc = rproc;
q6v5->dev = &pdev->dev;
@@ -263,6 +264,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
init_completion(&q6v5->start_done);
init_completion(&q6v5->stop_done);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ q6v5->rmb_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(q6v5->rmb_base))
+ q6v5->rmb_base = NULL;
+ } else
+ q6v5->rmb_base = NULL;
+
q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
if (q6v5->wdog_irq < 0)
return q6v5->wdog_irq;
diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h
index 5a859c41896e..95824d5b64ce 100644
--- a/drivers/remoteproc/qcom_q6v5.h
+++ b/drivers/remoteproc/qcom_q6v5.h
@@ -7,6 +7,12 @@
#include <linux/completion.h>
#include <linux/soc/qcom/qcom_aoss.h>
+#define RMB_BOOT_WAIT_REG 0x8
+#define RMB_BOOT_CONT_REG 0xC
+#define RMB_Q6_BOOT_STATUS_REG 0x10
+
+#define RMB_POLL_MAX_TIMES 250
+
struct icc_path;
struct rproc;
struct qcom_smem_state;
@@ -16,6 +22,8 @@ struct qcom_q6v5 {
struct device *dev;
struct rproc *rproc;
+ void __iomem *rmb_base;
+
struct qcom_smem_state *state;
struct qmp *qmp;
--
2.25.1
Some chipsets will have DSPs which will have begun running prior
to linux booting, so add support to late attach these DSPs by
adding support for:
- run-time checking of an offline or running DSP via rmb register
- a late attach framework to attach to the running DSP
- a handshake mechanism to ensure full and proper booting via rmb
Signed-off-by: Melody Olvera <[email protected]>
---
drivers/remoteproc/qcom_q6v5_pas.c | 103 ++++++++++++++++++++++++++++-
1 file changed, 102 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 0871108fb4dc..e22be6a029a8 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -242,10 +242,89 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
return ret;
}
+static int adsp_attach(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+ int i, ret;
+
+ ret = qcom_q6v5_prepare(&adsp->q6v5);
+ if (ret)
+ return ret;
+
+ ret = adsp_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+ if (ret < 0)
+ goto disable_irqs;
+
+ ret = clk_prepare_enable(adsp->xo);
+ if (ret)
+ goto disable_proxy_pds;
+
+ ret = clk_prepare_enable(adsp->aggre2_clk);
+ if (ret)
+ goto disable_xo_clk;
+
+ if (adsp->cx_supply) {
+ ret = regulator_enable(adsp->cx_supply);
+ if (ret)
+ goto disable_aggre2_clk;
+ }
+
+ if (adsp->px_supply) {
+ ret = regulator_enable(adsp->px_supply);
+ if (ret)
+ goto disable_cx_supply;
+ }
+
+ /* if needed, signal Q6 to continute booting */
+ if (adsp->q6v5.rmb_base) {
+ for (i = 0; i < RMB_POLL_MAX_TIMES; i++) {
+ if (readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
+ writel_relaxed(1, adsp->q6v5.rmb_base + RMB_BOOT_CONT_REG);
+ break;
+ }
+ msleep(20);
+ }
+
+ if (!readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
+ dev_err(adsp->dev, "Didn't get rmb signal from %s\n", rproc->name);
+ goto disable_px_supply;
+ }
+ }
+
+ ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
+ if (ret == -ETIMEDOUT) {
+ dev_err(adsp->dev, "start timed out\n");
+ qcom_scm_pas_shutdown(adsp->pas_id);
+ goto disable_px_supply;
+ }
+
+ return 0;
+
+disable_px_supply:
+ if (adsp->px_supply)
+ regulator_disable(adsp->px_supply);
+disable_cx_supply:
+ if (adsp->cx_supply)
+ regulator_disable(adsp->cx_supply);
+disable_aggre2_clk:
+ clk_disable_unprepare(adsp->aggre2_clk);
+disable_xo_clk:
+ clk_disable_unprepare(adsp->xo);
+disable_proxy_pds:
+ adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+disable_irqs:
+ qcom_q6v5_unprepare(&adsp->q6v5);
+
+ /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
+ adsp->firmware = NULL;
+
+ return ret;
+}
+
static int adsp_start(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
- int ret;
+ int i, ret;
ret = qcom_q6v5_prepare(&adsp->q6v5);
if (ret)
@@ -304,6 +383,22 @@ static int adsp_start(struct rproc *rproc)
goto release_pas_metadata;
}
+ /* if needed, signal Q6 to continute booting */
+ if (adsp->q6v5.rmb_base) {
+ for (i = 0; i < RMB_POLL_MAX_TIMES; i++) {
+ if (readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
+ writel_relaxed(1, adsp->q6v5.rmb_base + RMB_BOOT_CONT_REG);
+ break;
+ }
+ msleep(20);
+ }
+
+ if (!readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
+ dev_err(adsp->dev, "Didn't get rmb signal from %s\n", rproc->name);
+ goto release_pas_metadata;
+ }
+ }
+
ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) {
dev_err(adsp->dev, "start timed out\n");
@@ -413,6 +508,7 @@ static unsigned long adsp_panic(struct rproc *rproc)
static const struct rproc_ops adsp_ops = {
.unprepare = adsp_unprepare,
.start = adsp_start,
+ .attach = adsp_attach,
.stop = adsp_stop,
.da_to_va = adsp_da_to_va,
.parse_fw = qcom_register_dump_segments,
@@ -423,6 +519,7 @@ static const struct rproc_ops adsp_ops = {
static const struct rproc_ops adsp_minidump_ops = {
.unprepare = adsp_unprepare,
.start = adsp_start,
+ .attach = adsp_attach,
.stop = adsp_stop,
.da_to_va = adsp_da_to_va,
.load = adsp_load,
@@ -728,6 +825,10 @@ static int adsp_probe(struct platform_device *pdev)
if (ret)
goto detach_proxy_pds;
+ if (adsp->q6v5.rmb_base &&
+ readl_relaxed(adsp->q6v5.rmb_base + RMB_Q6_BOOT_STATUS_REG))
+ rproc->state = RPROC_DETACHED;
+
qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
adsp->sysmon = qcom_add_sysmon_subdev(rproc,
--
2.25.1
From: Gokul Krishna Krishnakumar <[email protected]>
When booting with split binaries, it may be that the offset of the first
program header lies inside the mdt's filesize, in this case the loader
would incorrectly assume that the bins were not split. The loading would
then continue on and fail for split bins. This change updates the logic used
by the mdt loader to understand whether the firmware images are split or not
by checking if each programs header's segment lies within the file or not.
Signed-off-by: Gokul Krishna Krishnakumar <[email protected]>
Signed-off-by: Melody Olvera <[email protected]>
---
drivers/soc/qcom/mdt_loader.c | 64 +++++++++++++++++++----------------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index 33dd8c315eb7..3aadce299c02 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -31,6 +31,26 @@ static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
return true;
}
+static bool qcom_mdt_bins_are_split(const struct firmware *fw)
+{
+ const struct elf32_phdr *phdrs;
+ const struct elf32_hdr *ehdr;
+ uint64_t seg_start, seg_end;
+ int i;
+
+ ehdr = (struct elf32_hdr *)fw->data;
+ phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ seg_start = phdrs[i].p_offset;
+ seg_end = phdrs[i].p_offset + phdrs[i].p_filesz;
+ if (seg_start > fw->size || seg_end > fw->size)
+ return true;
+ }
+
+ return false;
+}
+
static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
unsigned int segment, const char *fw_name,
struct device *dev)
@@ -167,23 +187,13 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
/* Copy ELF header */
memcpy(data, fw->data, ehdr_size);
- if (ehdr_size + hash_size == fw->size) {
- /* Firmware is split and hash is packed following the ELF header */
- hash_offset = phdrs[0].p_filesz;
- memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
- } else if (phdrs[hash_segment].p_offset + hash_size <= fw->size) {
- /* Hash is in its own segment, but within the loaded file */
+
+ if (qcom_mdt_bins_are_split(fw)) {
+ ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
+ } else {
hash_offset = phdrs[hash_segment].p_offset;
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
- } else {
- /* Hash is in its own segment, beyond the loaded file */
- ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
- if (ret) {
- kfree(data);
- return ERR_PTR(ret);
- }
}
-
*data_len = ehdr_size + hash_size;
return data;
@@ -270,6 +280,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
phys_addr_t min_addr = PHYS_ADDR_MAX;
ssize_t offset;
bool relocate = false;
+ bool is_split;
void *ptr;
int ret = 0;
int i;
@@ -277,6 +288,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
if (!fw || !mem_region || !mem_phys || !mem_size)
return -EINVAL;
+ is_split = qcom_mdt_bins_are_split(fw);
ehdr = (struct elf32_hdr *)fw->data;
phdrs = (struct elf32_phdr *)(ehdr + 1);
@@ -330,22 +342,16 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
ptr = mem_region + offset;
- if (phdr->p_filesz && phdr->p_offset < fw->size &&
- phdr->p_offset + phdr->p_filesz <= fw->size) {
- /* Firmware is large enough to be non-split */
- if (phdr->p_offset + phdr->p_filesz > fw->size) {
- dev_err(dev, "file %s segment %d would be truncated\n",
- fw_name, i);
- ret = -EINVAL;
- break;
+ if (phdr->p_filesz) {
+ if (!is_split) {
+ /* Firmware is large enough to be non-split */
+ memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
+ } else {
+ /* Firmware not large enough, load split-out segments */
+ ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
+ if (ret)
+ break;
}
-
- memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
- } else if (phdr->p_filesz) {
- /* Firmware not large enough, load split-out segments */
- ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
- if (ret)
- break;
}
if (phdr->p_memsz > phdr->p_filesz)
--
2.25.1
Add the compatible and data for the mpss found in the QDU1000 and
QRU1000 SoCs. These platforms require the driver to complete a modem
handshake using the RMB registers provided.
Signed-off-by: Melody Olvera <[email protected]>
---
drivers/remoteproc/qcom_q6v5_pas.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index e22be6a029a8..e7c40e757b86 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -972,6 +972,27 @@ static const struct adsp_data msm8996_adsp_resource = {
.ssctl_id = 0x14,
};
+static const struct adsp_data qdu1000_mpss_resource = {
+ .crash_reason_smem = 421,
+ .firmware_name = "modem.mdt",
+ .dtb_firmware_name = "modem_dtb.mdt",
+ .pas_id = 4,
+ .dtb_pas_id = 0x26,
+ .minidump_id = 3,
+ .auto_boot = false,
+ .decrypt_shutdown = true,
+ .proxy_pd_names = (char*[]) {
+ "cx",
+ "mss",
+ NULL
+ },
+ .load_state = "modem",
+ .ssr_name = "mpss",
+ .sysmon_name = "modem",
+ .ssctl_id = 0x12,
+ .region_assign_idx = 2,
+};
+
static const struct adsp_data cdsp_resource_init = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
@@ -1291,6 +1312,7 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init },
{ .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
+ { .compatible = "qcom,qdu1000-mpss-pas", .data = &qdu1000_mpss_resource },
{ .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
{ .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init},
{ .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
--
2.25.1
This documents the compatible for the component used to boot the
MPSS on the QDU1000 and QRU1000 SoCs.
The QDU1000 and QRU1000 mpss boot process now requires the specification
of an RMB register space to complete the handshake needed to start or
attach the mpss.
Signed-off-by: Melody Olvera <[email protected]>
---
.../remoteproc/qcom,qdu1000-mpss-pas.yaml | 130 ++++++++++++++++++
1 file changed, 130 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
new file mode 100644
index 000000000000..9cb4296c1fa6
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
@@ -0,0 +1,130 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,qdu1000-mpss-pas.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QDU1000 Modem Peripheral Authentication Service
+
+maintainers:
+ - Melody Olvera <[email protected]>
+
+description:
+ Qualcomm QDU1000 SoC Peripheral Authentication Service loads and boots firmware
+ on the Qualcomm DSP Hexagon core.
+
+properties:
+ compatible:
+ enum:
+ - qcom,qdu1000-mpss-pas
+
+ reg:
+ maxItems: 2
+
+ clocks:
+ items:
+ - description: XO clock
+
+ clock-names:
+ items:
+ - const: xo
+
+ qcom,qmp:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Reference to the AOSS side-channel message RAM.
+
+ smd-edge: false
+
+ firmware-name:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ items:
+ - description: Firmware name of the Hexagon core
+ - description: Firmware name of the Hexagon Devicetree
+
+ memory-region:
+ items:
+ - description: Memory region for main Firmware authentication
+ - description: Memory region for Devicetree Firmware authentication
+ - description: DSM Memory region
+
+ interrupts:
+ minItems: 6
+
+ interrupt-names:
+ minItems: 6
+
+ interconnects:
+ minItems: 1
+
+ power-domains:
+ items:
+ - description: CX power domain
+ - description: MSS power domain
+
+ power-domain-names:
+ items:
+ - const: cx
+ - const: mss
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: /schemas/remoteproc/qcom,pas-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ #include <dt-bindings/interconnect/qcom,qdu1000-rpmh.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/mailbox/qcom-ipcc.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+
+ remoteproc@4080000 {
+ compatible = "qcom,qdu1000-mpss-pas";
+ reg = <0x4080000 0x4040>,
+ <0x4180000 0x1000>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK>;
+ clock-names = "xo";
+
+ interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_modem_in 3 IRQ_TYPE_EDGE_RISING>,
+ <&smp2p_modem_in 7 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal", "ready", "handover",
+ "stop-ack", "shutdown-ack";
+
+ memory-region = <&mpss_mem>, <&dtb_mpss_mem>, <&mpss_dsm_mem>;
+
+ firmware-name = "qcom/qdu1000/modem.mbn",
+ "qcom/qdu1000/modem_dtb.mbn";
+
+ power-domains = <&rpmhpd QDU1000_CX>,
+ <&rpmhpd QDU1000_MSS>;
+ power-domain-names = "cx", "mss";
+
+ interconnects = <&mc_virt MASTER_LLCC &mc_virt SLAVE_EBI1>;
+
+ qcom,qmp = <&aoss_qmp>;
+
+ qcom,smem-states = <&smp2p_adsp_out 0>;
+ qcom,smem-state-names = "stop";
+
+ glink-edge {
+ interrupts-extended = <&ipcc IPCC_CLIENT_MPSS
+ IPCC_MPROC_SIGNAL_GLINK_QMP
+ IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&ipcc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+ label = "modem";
+ qcom,remote-pid = <2>;
+
+ };
+ };
--
2.25.1
Hi Melody,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on dc837c1a5137a8cf2e9432c1891392b6a66f4d8d]
url: https://github.com/intel-lab-lkp/linux/commits/Melody-Olvera/dt-bindings-firmware-qcom-scm-Update-QDU1000-QRU1000-compatible/20230307-071438
base: dc837c1a5137a8cf2e9432c1891392b6a66f4d8d
patch link: https://lore.kernel.org/r/20230306231202.12223-5-quic_molvera%40quicinc.com
patch subject: [PATCH v2 4/7] soc: qcom: mdt_loader: Enhance split binary detection
config: arm-allmodconfig (https://download.01.org/0day-ci/archive/20230308/[email protected]/config)
compiler: arm-linux-gnueabi-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/3964310160b68a6246f85828ecbcebf1fb9137a7
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Melody-Olvera/dt-bindings-firmware-qcom-scm-Update-QDU1000-QRU1000-compatible/20230307-071438
git checkout 3964310160b68a6246f85828ecbcebf1fb9137a7
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arm olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/soc/qcom/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Link: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
drivers/soc/qcom/mdt_loader.c: In function 'qcom_mdt_read_metadata':
>> drivers/soc/qcom/mdt_loader.c:156:17: warning: variable 'ret' set but not used [-Wunused-but-set-variable]
156 | ssize_t ret;
| ^~~
vim +/ret +156 drivers/soc/qcom/mdt_loader.c
051fb70fd4ea40f drivers/remoteproc/qcom_mdt_loader.c Bjorn Andersson 2016-06-20 126
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 127 /**
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 128 * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 129 * @fw: firmware of mdt header or mbn
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 130 * @data_len: length of the read metadata blob
d11a34a404ee556 drivers/soc/qcom/mdt_loader.c Krzysztof Kozlowski 2022-05-19 131 * @fw_name: name of the firmware, for construction of segment file names
d11a34a404ee556 drivers/soc/qcom/mdt_loader.c Krzysztof Kozlowski 2022-05-19 132 * @dev: device handle to associate resources with
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 133 *
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 134 * The mechanism that performs the authentication of the loading firmware
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 135 * expects an ELF header directly followed by the segment of hashes, with no
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 136 * padding inbetween. This function allocates a chunk of memory for this pair
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 137 * and copy the two pieces into the buffer.
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 138 *
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 139 * In the case of split firmware the hash is found directly following the ELF
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 140 * header, rather than at p_offset described by the second program header.
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 141 *
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 142 * The caller is responsible to free (kfree()) the returned pointer.
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 143 *
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 144 * Return: pointer to data, or ERR_PTR()
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 145 */
8bd42e2341a7857 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 146 void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
8bd42e2341a7857 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 147 const char *fw_name, struct device *dev)
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 148 {
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 149 const struct elf32_phdr *phdrs;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 150 const struct elf32_hdr *ehdr;
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 151 unsigned int hash_segment = 0;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 152 size_t hash_offset;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 153 size_t hash_size;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 154 size_t ehdr_size;
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 155 unsigned int i;
8bd42e2341a7857 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 @156 ssize_t ret;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 157 void *data;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 158
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 159 ehdr = (struct elf32_hdr *)fw->data;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 160 phdrs = (struct elf32_phdr *)(ehdr + 1);
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 161
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 162 if (ehdr->e_phnum < 2)
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 163 return ERR_PTR(-EINVAL);
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 164
833d51d7c66d670 drivers/soc/qcom/mdt_loader.c Shawn Guo 2021-08-28 165 if (phdrs[0].p_type == PT_LOAD)
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 166 return ERR_PTR(-EINVAL);
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 167
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 168 for (i = 1; i < ehdr->e_phnum; i++) {
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 169 if ((phdrs[i].p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) {
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 170 hash_segment = i;
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 171 break;
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 172 }
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 173 }
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 174
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 175 if (!hash_segment) {
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 176 dev_err(dev, "no hash segment found in %s\n", fw_name);
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 177 return ERR_PTR(-EINVAL);
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 178 }
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 179
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 180 ehdr_size = phdrs[0].p_filesz;
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 181 hash_size = phdrs[hash_segment].p_filesz;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 182
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 183 data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 184 if (!data)
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 185 return ERR_PTR(-ENOMEM);
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 186
8bd42e2341a7857 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 187 /* Copy ELF header */
8bd42e2341a7857 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 188 memcpy(data, fw->data, ehdr_size);
8bd42e2341a7857 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 189
3964310160b68a6 drivers/soc/qcom/mdt_loader.c Gokul Krishna Krishnakumar 2023-03-06 190
3964310160b68a6 drivers/soc/qcom/mdt_loader.c Gokul Krishna Krishnakumar 2023-03-06 191 if (qcom_mdt_bins_are_split(fw)) {
3964310160b68a6 drivers/soc/qcom/mdt_loader.c Gokul Krishna Krishnakumar 2023-03-06 192 ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
3964310160b68a6 drivers/soc/qcom/mdt_loader.c Gokul Krishna Krishnakumar 2023-03-06 193 } else {
64fb5eb87d5815f drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 194 hash_offset = phdrs[hash_segment].p_offset;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 195 memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
8bd42e2341a7857 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2022-01-27 196 }
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 197 *data_len = ehdr_size + hash_size;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 198
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 199 return data;
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 200 }
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 201 EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
498b98e939007f8 drivers/soc/qcom/mdt_loader.c Bjorn Andersson 2019-06-21 202
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests
On 07/03/2023 00:11, Melody Olvera wrote:
> This documents the compatible for the component used to boot the
Do not use "This commit/patch".
https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
> MPSS on the QDU1000 and QRU1000 SoCs.
>
> The QDU1000 and QRU1000 mpss boot process now requires the specification
> of an RMB register space to complete the handshake needed to start or
> attach the mpss.
>
> Signed-off-by: Melody Olvera <[email protected]>
> ---
> .../remoteproc/qcom,qdu1000-mpss-pas.yaml | 130 ++++++++++++++++++
> 1 file changed, 130 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
> new file mode 100644
> index 000000000000..9cb4296c1fa6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
> @@ -0,0 +1,130 @@
> +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/remoteproc/qcom,qdu1000-mpss-pas.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm QDU1000 Modem Peripheral Authentication Service
> +
> +maintainers:
> + - Melody Olvera <[email protected]>
> +
> +description:
> + Qualcomm QDU1000 SoC Peripheral Authentication Service loads and boots firmware
> + on the Qualcomm DSP Hexagon core.
> +
> +properties:
> + compatible:
> + enum:
> + - qcom,qdu1000-mpss-pas
> +
> + reg:
> + maxItems: 2
You need to list the items instead (just like for clocks).
> +
> + clocks:
> + items:
> + - description: XO clock
> +
> + clock-names:
> + items:
> + - const: xo
> +
> + qcom,qmp:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: Reference to the AOSS side-channel message RAM.
> +
> + smd-edge: false
> +
> + firmware-name:
> + $ref: /schemas/types.yaml#/definitions/string-array
You can now drop the $ref.
> + items:
> + - description: Firmware name of the Hexagon core
> + - description: Firmware name of the Hexagon Devicetree
> +
> + memory-region:
> + items:
> + - description: Memory region for main Firmware authentication
> + - description: Memory region for Devicetree Firmware authentication
> + - description: DSM Memory region
> +
> + interrupts:
> + minItems: 6
> +
> + interrupt-names:
> + minItems: 6
> +
> + interconnects:
> + minItems: 1
maxItems instead
> +
> + power-domains:
> + items:
> + - description: CX power domain
> + - description: MSS power domain
> +
> + power-domain-names:
> + items:
> + - const: cx
> + - const: mss
> +
> +required:
> + - compatible
> + - reg
memory-region
(I fixed other bindings)
> +
> +allOf:
> + - $ref: /schemas/remoteproc/qcom,pas-common.yaml#
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/qcom,rpmh.h>
> + #include <dt-bindings/interconnect/qcom,qdu1000-rpmh.h>
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> + #include <dt-bindings/mailbox/qcom-ipcc.h>
> + #include <dt-bindings/power/qcom-rpmpd.h>
> +
> + remoteproc@4080000 {
> + compatible = "qcom,qdu1000-mpss-pas";
> + reg = <0x4080000 0x4040>,
> + <0x4180000 0x1000>;
> +
> + clocks = <&rpmhcc RPMH_CXO_CLK>;
> + clock-names = "xo";
> +
> + interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
> + <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>,
> + <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>,
> + <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>,
> + <&smp2p_modem_in 3 IRQ_TYPE_EDGE_RISING>,
> + <&smp2p_modem_in 7 IRQ_TYPE_EDGE_RISING>;
> + interrupt-names = "wdog", "fatal", "ready", "handover",
> + "stop-ack", "shutdown-ack";
> +
> + memory-region = <&mpss_mem>, <&dtb_mpss_mem>, <&mpss_dsm_mem>;
> +
> + firmware-name = "qcom/qdu1000/modem.mbn",
> + "qcom/qdu1000/modem_dtb.mbn";
> +
> + power-domains = <&rpmhpd QDU1000_CX>,
> + <&rpmhpd QDU1000_MSS>;
> + power-domain-names = "cx", "mss";
> +
> + interconnects = <&mc_virt MASTER_LLCC &mc_virt SLAVE_EBI1>;
> +
> + qcom,qmp = <&aoss_qmp>;
> +
> + qcom,smem-states = <&smp2p_adsp_out 0>;
> + qcom,smem-state-names = "stop";
> +
> + glink-edge {
> + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS
> + IPCC_MPROC_SIGNAL_GLINK_QMP
> + IRQ_TYPE_EDGE_RISING>;
> + mboxes = <&ipcc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_GLINK_QMP>;
> +
> + label = "modem";
> + qcom,remote-pid = <2>;
> +
Drop stray blank line
> + };
> + };
Best regards,
Krzysztof
On 09/03/2023 09:33, Krzysztof Kozlowski wrote:
> On 07/03/2023 00:11, Melody Olvera wrote:
>> This documents the compatible for the component used to boot the
>
> Do not use "This commit/patch".
> https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
>
>> MPSS on the QDU1000 and QRU1000 SoCs.
>>
>> The QDU1000 and QRU1000 mpss boot process now requires the specification
>> of an RMB register space to complete the handshake needed to start or
>> attach the mpss.
>>
>> Signed-off-by: Melody Olvera <[email protected]>
>> ---
>> .../remoteproc/qcom,qdu1000-mpss-pas.yaml | 130 ++++++++++++++++++
>> 1 file changed, 130 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
>> new file mode 100644
>> index 000000000000..9cb4296c1fa6
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
>> @@ -0,0 +1,130 @@
>> +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/remoteproc/qcom,qdu1000-mpss-pas.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm QDU1000 Modem Peripheral Authentication Service
>> +
>> +maintainers:
>> + - Melody Olvera <[email protected]>
>> +
>> +description:
>> + Qualcomm QDU1000 SoC Peripheral Authentication Service loads and boots firmware
>> + on the Qualcomm DSP Hexagon core.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - qcom,qdu1000-mpss-pas
>> +
>> + reg:
>> + maxItems: 2
>
> You need to list the items instead (just like for clocks).
>
>> +
>> + clocks:
>> + items:
>> + - description: XO clock
>> +
>> + clock-names:
>> + items:
>> + - const: xo
>> +
>> + qcom,qmp:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description: Reference to the AOSS side-channel message RAM.
>> +
>> + smd-edge: false
>> +
>> + firmware-name:
>> + $ref: /schemas/types.yaml#/definitions/string-array
>
> You can now drop the $ref.
>
>> + items:
>> + - description: Firmware name of the Hexagon core
>> + - description: Firmware name of the Hexagon Devicetree
>> +
>> + memory-region:
>> + items:
>> + - description: Memory region for main Firmware authentication
>> + - description: Memory region for Devicetree Firmware authentication
>> + - description: DSM Memory region
>> +
>> + interrupts:
>> + minItems: 6
>> +
>> + interrupt-names:
>> + minItems: 6
>> +
>> + interconnects:
>> + minItems: 1
>
> maxItems instead
Wait, I already commented on this... Some other comments also ignored.
This is a friendly reminder during the review process.
It seems my previous comments were not fully addressed. Maybe my
feedback got lost between the quotes, maybe you just forgot to apply it.
Please go back to the previous discussion and either implement all
requested changes or keep discussing them.
Thank you.
Best regards,
Krzysztof
On 3/9/2023 12:33 AM, Krzysztof Kozlowski wrote:
> On 07/03/2023 00:11, Melody Olvera wrote:
>> This documents the compatible for the component used to boot the
> Do not use "This commit/patch".
> https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
Ok.
>
>> MPSS on the QDU1000 and QRU1000 SoCs.
>>
>> The QDU1000 and QRU1000 mpss boot process now requires the specification
>> of an RMB register space to complete the handshake needed to start or
>> attach the mpss.
>>
>> Signed-off-by: Melody Olvera <[email protected]>
>> ---
>> .../remoteproc/qcom,qdu1000-mpss-pas.yaml | 130 ++++++++++++++++++
>> 1 file changed, 130 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
>> new file mode 100644
>> index 000000000000..9cb4296c1fa6
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/remoteproc/qcom,qdu1000-mpss-pas.yaml
>> @@ -0,0 +1,130 @@
>> +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/remoteproc/qcom,qdu1000-mpss-pas.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm QDU1000 Modem Peripheral Authentication Service
>> +
>> +maintainers:
>> + - Melody Olvera <[email protected]>
>> +
>> +description:
>> + Qualcomm QDU1000 SoC Peripheral Authentication Service loads and boots firmware
>> + on the Qualcomm DSP Hexagon core.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - qcom,qdu1000-mpss-pas
>> +
>> + reg:
>> + maxItems: 2
> You need to list the items instead (just like for clocks).
Will do.
>
>> +
>> + clocks:
>> + items:
>> + - description: XO clock
>> +
>> + clock-names:
>> + items:
>> + - const: xo
>> +
>> + qcom,qmp:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description: Reference to the AOSS side-channel message RAM.
>> +
>> + smd-edge: false
>> +
>> + firmware-name:
>> + $ref: /schemas/types.yaml#/definitions/string-array
> You can now drop the $ref.
Ok will drop.
>
>> + items:
>> + - description: Firmware name of the Hexagon core
>> + - description: Firmware name of the Hexagon Devicetree
>> +
>> + memory-region:
>> + items:
>> + - description: Memory region for main Firmware authentication
>> + - description: Memory region for Devicetree Firmware authentication
>> + - description: DSM Memory region
>> +
>> + interrupts:
>> + minItems: 6
>> +
>> + interrupt-names:
>> + minItems: 6
>> +
>> + interconnects:
>> + minItems: 1
> maxItems instead
Last comments said to drop this since it's redundant from qcom,pas-common.yaml. Will drop per
our discussion on https://lore.kernel.org/all/[email protected]/.
>
>> +
>> + power-domains:
>> + items:
>> + - description: CX power domain
>> + - description: MSS power domain
>> +
>> + power-domain-names:
>> + items:
>> + - const: cx
>> + - const: mss
>> +
>> +required:
>> + - compatible
>> + - reg
> memory-region
>
> (I fixed other bindings)
Ah sounds good. Will add here.
>
>> +
>> +allOf:
>> + - $ref: /schemas/remoteproc/qcom,pas-common.yaml#
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/clock/qcom,rpmh.h>
>> + #include <dt-bindings/interconnect/qcom,qdu1000-rpmh.h>
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + #include <dt-bindings/interrupt-controller/irq.h>
>> + #include <dt-bindings/mailbox/qcom-ipcc.h>
>> + #include <dt-bindings/power/qcom-rpmpd.h>
>> +
>> + remoteproc@4080000 {
>> + compatible = "qcom,qdu1000-mpss-pas";
>> + reg = <0x4080000 0x4040>,
>> + <0x4180000 0x1000>;
>> +
>> + clocks = <&rpmhcc RPMH_CXO_CLK>;
>> + clock-names = "xo";
>> +
>> + interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
>> + <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>,
>> + <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>,
>> + <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>,
>> + <&smp2p_modem_in 3 IRQ_TYPE_EDGE_RISING>,
>> + <&smp2p_modem_in 7 IRQ_TYPE_EDGE_RISING>;
>> + interrupt-names = "wdog", "fatal", "ready", "handover",
>> + "stop-ack", "shutdown-ack";
>> +
>> + memory-region = <&mpss_mem>, <&dtb_mpss_mem>, <&mpss_dsm_mem>;
>> +
>> + firmware-name = "qcom/qdu1000/modem.mbn",
>> + "qcom/qdu1000/modem_dtb.mbn";
>> +
>> + power-domains = <&rpmhpd QDU1000_CX>,
>> + <&rpmhpd QDU1000_MSS>;
>> + power-domain-names = "cx", "mss";
>> +
>> + interconnects = <&mc_virt MASTER_LLCC &mc_virt SLAVE_EBI1>;
>> +
>> + qcom,qmp = <&aoss_qmp>;
>> +
>> + qcom,smem-states = <&smp2p_adsp_out 0>;
>> + qcom,smem-state-names = "stop";
>> +
>> + glink-edge {
>> + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS
>> + IPCC_MPROC_SIGNAL_GLINK_QMP
>> + IRQ_TYPE_EDGE_RISING>;
>> + mboxes = <&ipcc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_GLINK_QMP>;
>> +
>> + label = "modem";
>> + qcom,remote-pid = <2>;
>> +
> Drop stray blank line
Got it. Also per https://lore.kernel.org/all/[email protected]/.
Apologies for missing some comments.
Thanks,
Melody
>> + };
>> + };
> Best regards,
> Krzysztof
>
On Mon, Mar 06, 2023 at 03:11:59PM -0800, Melody Olvera wrote:
> From: Gokul Krishna Krishnakumar <[email protected]>
>
> When booting with split binaries, it may be that the offset of the first
> program header lies inside the mdt's filesize, in this case the loader
> would incorrectly assume that the bins were not split. The loading would
> then continue on and fail for split bins.
Can you please be more explicit about the scenario you're having
problems with?
Is the problem that the first segment is represented in both the .mdt
and .b01, but different? Or is it that you find the hash in both .mdt
abd .b01, but only one of them is valid?
> This change updates the logic used
> by the mdt loader to understand whether the firmware images are split or not
> by checking if each programs header's segment lies within the file or not.
>
> Signed-off-by: Gokul Krishna Krishnakumar <[email protected]>
> Signed-off-by: Melody Olvera <[email protected]>
> ---
> drivers/soc/qcom/mdt_loader.c | 64 +++++++++++++++++++----------------
> 1 file changed, 35 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
> index 33dd8c315eb7..3aadce299c02 100644
> --- a/drivers/soc/qcom/mdt_loader.c
> +++ b/drivers/soc/qcom/mdt_loader.c
> @@ -31,6 +31,26 @@ static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
> return true;
> }
>
> +static bool qcom_mdt_bins_are_split(const struct firmware *fw)
> +{
> + const struct elf32_phdr *phdrs;
> + const struct elf32_hdr *ehdr;
> + uint64_t seg_start, seg_end;
> + int i;
> +
> + ehdr = (struct elf32_hdr *)fw->data;
> + phdrs = (struct elf32_phdr *)(ehdr + 1);
> +
> + for (i = 0; i < ehdr->e_phnum; i++) {
> + seg_start = phdrs[i].p_offset;
> + seg_end = phdrs[i].p_offset + phdrs[i].p_filesz;
> + if (seg_start > fw->size || seg_end > fw->size)
> + return true;
> + }
> +
> + return false;
> +}
> +
> static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
> unsigned int segment, const char *fw_name,
> struct device *dev)
> @@ -167,23 +187,13 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
> /* Copy ELF header */
> memcpy(data, fw->data, ehdr_size);
>
The existing code handles 3 cases:
> - if (ehdr_size + hash_size == fw->size) {
1) File is split, but hash resides with the ELF header in the .mdt
> - /* Firmware is split and hash is packed following the ELF header */
> - hash_offset = phdrs[0].p_filesz;
> - memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
> - } else if (phdrs[hash_segment].p_offset + hash_size <= fw->size) {
2) The hash segment exists in a segment of its own, but in the loaded
image.
> - /* Hash is in its own segment, but within the loaded file */
> +
> + if (qcom_mdt_bins_are_split(fw)) {
> + ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
> + } else {
> hash_offset = phdrs[hash_segment].p_offset;
> memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
> - } else {
3) The image is split, and the hash segment resides in it's own file.
Afaict the updated logic maintains #2 and #3, but drops #1. Please
review the git history to see if you can determine which target this
case exists with - and ask for someone to specifically verify your
change there.
Perhaps all your change is doing is removing case #1, in which case this
should be clear in the commit message; and we need to validate that your
new assumptions holds.
> - /* Hash is in its own segment, beyond the loaded file */
> - ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
For some reason you reversed the condition and got this out of the else
(seems like an unnecessary change)...but in the process you lost the
error handling below.
> - if (ret) {
> - kfree(data);
> - return ERR_PTR(ret);
> - }
> }
> -
> *data_len = ehdr_size + hash_size;
>
> return data;
> @@ -270,6 +280,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
> phys_addr_t min_addr = PHYS_ADDR_MAX;
> ssize_t offset;
> bool relocate = false;
> + bool is_split;
> void *ptr;
> int ret = 0;
> int i;
> @@ -277,6 +288,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
> if (!fw || !mem_region || !mem_phys || !mem_size)
> return -EINVAL;
>
> + is_split = qcom_mdt_bins_are_split(fw);
> ehdr = (struct elf32_hdr *)fw->data;
> phdrs = (struct elf32_phdr *)(ehdr + 1);
>
> @@ -330,22 +342,16 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
>
> ptr = mem_region + offset;
>
> - if (phdr->p_filesz && phdr->p_offset < fw->size &&
> - phdr->p_offset + phdr->p_filesz <= fw->size) {
> - /* Firmware is large enough to be non-split */
> - if (phdr->p_offset + phdr->p_filesz > fw->size) {
> - dev_err(dev, "file %s segment %d would be truncated\n",
> - fw_name, i);
> - ret = -EINVAL;
> - break;
> + if (phdr->p_filesz) {
If you just change the condition (phr->p_filesz && !issplit), then your
patch becomes easier to read.
Regards,
Bjorn
> + if (!is_split) {
> + /* Firmware is large enough to be non-split */
> + memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
> + } else {
> + /* Firmware not large enough, load split-out segments */
> + ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
> + if (ret)
> + break;
> }
> -
> - memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
> - } else if (phdr->p_filesz) {
> - /* Firmware not large enough, load split-out segments */
> - ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
> - if (ret)
> - break;
> }
>
> if (phdr->p_memsz > phdr->p_filesz)
> --
> 2.25.1
>
On Mon, Mar 06, 2023 at 03:12:00PM -0800, Melody Olvera wrote:
> When attaching a running Q6, the remoteproc driver needs a way
> to communicate with the Q6 using rmb registers, so allow the
> rmb register to be gotten from the device tree if present.
>
> Signed-off-by: Melody Olvera <[email protected]>
> ---
> drivers/remoteproc/qcom_q6v5.c | 9 +++++++++
> drivers/remoteproc/qcom_q6v5.h | 8 ++++++++
> 2 files changed, 17 insertions(+)
>
> diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
> index 192c7aa0e39e..e8c6be70ebfd 100644
> --- a/drivers/remoteproc/qcom_q6v5.c
> +++ b/drivers/remoteproc/qcom_q6v5.c
> @@ -254,6 +254,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
> void (*handover)(struct qcom_q6v5 *q6v5))
> {
> int ret;
> + struct resource *res;
>
> q6v5->rproc = rproc;
> q6v5->dev = &pdev->dev;
> @@ -263,6 +264,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
> init_completion(&q6v5->start_done);
> init_completion(&q6v5->stop_done);
>
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
In addition to the PAS driver, __func__ is being invoked by the non-PAS
ADSP and MPSS drivers as well, which both uses reg[1] for other
purposes. So this won't work.
Perhaps I'm missing some possibility of reuse, but it seems reasonable
for this to move to the pas-driver.
Thanks,
Bjorn
> + if (res) {
> + q6v5->rmb_base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(q6v5->rmb_base))
> + q6v5->rmb_base = NULL;
> + } else
> + q6v5->rmb_base = NULL;
> +
> q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
> if (q6v5->wdog_irq < 0)
> return q6v5->wdog_irq;
> diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h
> index 5a859c41896e..95824d5b64ce 100644
> --- a/drivers/remoteproc/qcom_q6v5.h
> +++ b/drivers/remoteproc/qcom_q6v5.h
> @@ -7,6 +7,12 @@
> #include <linux/completion.h>
> #include <linux/soc/qcom/qcom_aoss.h>
>
> +#define RMB_BOOT_WAIT_REG 0x8
> +#define RMB_BOOT_CONT_REG 0xC
> +#define RMB_Q6_BOOT_STATUS_REG 0x10
> +
> +#define RMB_POLL_MAX_TIMES 250
> +
> struct icc_path;
> struct rproc;
> struct qcom_smem_state;
> @@ -16,6 +22,8 @@ struct qcom_q6v5 {
> struct device *dev;
> struct rproc *rproc;
>
> + void __iomem *rmb_base;
> +
> struct qcom_smem_state *state;
> struct qmp *qmp;
>
> --
> 2.25.1
>
On Mon, Mar 06, 2023 at 03:12:01PM -0800, Melody Olvera wrote:
> Some chipsets will have DSPs which will have begun running prior
> to linux booting, so add support to late attach these DSPs by
> adding support for:
> - run-time checking of an offline or running DSP via rmb register
> - a late attach framework to attach to the running DSP
> - a handshake mechanism to ensure full and proper booting via rmb
>
> Signed-off-by: Melody Olvera <[email protected]>
> ---
> drivers/remoteproc/qcom_q6v5_pas.c | 103 ++++++++++++++++++++++++++++-
> 1 file changed, 102 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index 0871108fb4dc..e22be6a029a8 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -242,10 +242,89 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
> return ret;
> }
>
> +static int adsp_attach(struct rproc *rproc)
> +{
> + struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> + int i, ret;
> +
> + ret = qcom_q6v5_prepare(&adsp->q6v5);
> + if (ret)
> + return ret;
> +
> + ret = adsp_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
> + if (ret < 0)
> + goto disable_irqs;
> +
> + ret = clk_prepare_enable(adsp->xo);
> + if (ret)
> + goto disable_proxy_pds;
> +
> + ret = clk_prepare_enable(adsp->aggre2_clk);
> + if (ret)
> + goto disable_xo_clk;
> +
> + if (adsp->cx_supply) {
> + ret = regulator_enable(adsp->cx_supply);
> + if (ret)
> + goto disable_aggre2_clk;
> + }
> +
> + if (adsp->px_supply) {
> + ret = regulator_enable(adsp->px_supply);
> + if (ret)
> + goto disable_cx_supply;
> + }
> +
> + /* if needed, signal Q6 to continute booting */
> + if (adsp->q6v5.rmb_base) {
> + for (i = 0; i < RMB_POLL_MAX_TIMES; i++) {
> + if (readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
> + writel_relaxed(1, adsp->q6v5.rmb_base + RMB_BOOT_CONT_REG);
> + break;
> + }
> + msleep(20);
> + }
> +
> + if (!readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
> + dev_err(adsp->dev, "Didn't get rmb signal from %s\n", rproc->name);
> + goto disable_px_supply;
> + }
> + }
> +
> + ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
> + if (ret == -ETIMEDOUT) {
> + dev_err(adsp->dev, "start timed out\n");
> + qcom_scm_pas_shutdown(adsp->pas_id);
> + goto disable_px_supply;
> + }
> +
> + return 0;
> +
> +disable_px_supply:
> + if (adsp->px_supply)
> + regulator_disable(adsp->px_supply);
> +disable_cx_supply:
> + if (adsp->cx_supply)
> + regulator_disable(adsp->cx_supply);
> +disable_aggre2_clk:
> + clk_disable_unprepare(adsp->aggre2_clk);
> +disable_xo_clk:
> + clk_disable_unprepare(adsp->xo);
> +disable_proxy_pds:
> + adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
> +disable_irqs:
> + qcom_q6v5_unprepare(&adsp->q6v5);
> +
> + /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
> + adsp->firmware = NULL;
> +
> + return ret;
> +}
> +
> static int adsp_start(struct rproc *rproc)
> {
> struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> - int ret;
> + int i, ret;
>
> ret = qcom_q6v5_prepare(&adsp->q6v5);
> if (ret)
> @@ -304,6 +383,22 @@ static int adsp_start(struct rproc *rproc)
> goto release_pas_metadata;
> }
>
> + /* if needed, signal Q6 to continute booting */
Why does this come before the wait_for_start()? Is the DSP actually up
and running when you hit attach, or is it just loaded?
> + if (adsp->q6v5.rmb_base) {
Afaict this is copy-paste from attach, please move it to a helper
function.
> + for (i = 0; i < RMB_POLL_MAX_TIMES; i++) {
> + if (readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
> + writel_relaxed(1, adsp->q6v5.rmb_base + RMB_BOOT_CONT_REG);
> + break;
> + }
> + msleep(20);
> + }
> +
> + if (!readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
If you hit the break above, there should be no reason to read this
register again.
Seems cleaner to write this as:
ret = readl_poll_timeout();
if (ret < 0)
goto release;
writel(1, ...);
Regards,
Bjorn
> + dev_err(adsp->dev, "Didn't get rmb signal from %s\n", rproc->name);
> + goto release_pas_metadata;
> + }
> + }
> +
> ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
> if (ret == -ETIMEDOUT) {
> dev_err(adsp->dev, "start timed out\n");
> @@ -413,6 +508,7 @@ static unsigned long adsp_panic(struct rproc *rproc)
> static const struct rproc_ops adsp_ops = {
> .unprepare = adsp_unprepare,
> .start = adsp_start,
> + .attach = adsp_attach,
> .stop = adsp_stop,
> .da_to_va = adsp_da_to_va,
> .parse_fw = qcom_register_dump_segments,
> @@ -423,6 +519,7 @@ static const struct rproc_ops adsp_ops = {
> static const struct rproc_ops adsp_minidump_ops = {
> .unprepare = adsp_unprepare,
> .start = adsp_start,
> + .attach = adsp_attach,
> .stop = adsp_stop,
> .da_to_va = adsp_da_to_va,
> .load = adsp_load,
> @@ -728,6 +825,10 @@ static int adsp_probe(struct platform_device *pdev)
> if (ret)
> goto detach_proxy_pds;
>
> + if (adsp->q6v5.rmb_base &&
> + readl_relaxed(adsp->q6v5.rmb_base + RMB_Q6_BOOT_STATUS_REG))
> + rproc->state = RPROC_DETACHED;
> +
> qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
> qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
> adsp->sysmon = qcom_add_sysmon_subdev(rproc,
> --
> 2.25.1
>
On Mon, 6 Mar 2023 15:11:55 -0800, Melody Olvera wrote:
> This patchset adds support for the mpss found in the QDU1000 and QRU1000
> SoCs.
>
> The mpss boot process now supports late attach for an already running
> mpss. For this, it uses an RMB register space to perform a handshake
> with the mpss for the late attach process. This is implemented in the
> patches below. The patches also address issues with split binary
> detection to support loading of split binaries more robustly.
>
> [...]
Applied, thanks!
[1/7] dt-bindings: firmware: qcom,scm: Update QDU1000/QRU1000 compatible
commit: bbf97c274da60fcfbb8ebde70a1c3abc6102c709
[2/7] dt-bindings: soc: qcom: aoss: Document QDU1000/QRU1000 compatible
commit: 9559342891be54d9ffd13061022d9e5d24b2577a
Best regards,
--
Bjorn Andersson <[email protected]>
On 3/15/2023 7:17 PM, Bjorn Andersson wrote:
> On Mon, Mar 06, 2023 at 03:12:00PM -0800, Melody Olvera wrote:
>> When attaching a running Q6, the remoteproc driver needs a way
>> to communicate with the Q6 using rmb registers, so allow the
>> rmb register to be gotten from the device tree if present.
>>
>> Signed-off-by: Melody Olvera <[email protected]>
>> ---
>> drivers/remoteproc/qcom_q6v5.c | 9 +++++++++
>> drivers/remoteproc/qcom_q6v5.h | 8 ++++++++
>> 2 files changed, 17 insertions(+)
>>
>> diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
>> index 192c7aa0e39e..e8c6be70ebfd 100644
>> --- a/drivers/remoteproc/qcom_q6v5.c
>> +++ b/drivers/remoteproc/qcom_q6v5.c
>> @@ -254,6 +254,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
>> void (*handover)(struct qcom_q6v5 *q6v5))
>> {
>> int ret;
>> + struct resource *res;
>>
>> q6v5->rproc = rproc;
>> q6v5->dev = &pdev->dev;
>> @@ -263,6 +264,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
>> init_completion(&q6v5->start_done);
>> init_completion(&q6v5->stop_done);
>>
>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> In addition to the PAS driver, __func__ is being invoked by the non-PAS
> ADSP and MPSS drivers as well, which both uses reg[1] for other
> purposes. So this won't work.
>
> Perhaps I'm missing some possibility of reuse, but it seems reasonable
> for this to move to the pas-driver.
Yeah that's fairly sensible. I'll move this to the pas driver.
Thanks,
Melody
>
> Thanks,
> Bjorn
>
>> + if (res) {
>> + q6v5->rmb_base = devm_ioremap_resource(&pdev->dev, res);
>> + if (IS_ERR(q6v5->rmb_base))
>> + q6v5->rmb_base = NULL;
>> + } else
>> + q6v5->rmb_base = NULL;
>> +
>> q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
>> if (q6v5->wdog_irq < 0)
>> return q6v5->wdog_irq;
>> diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h
>> index 5a859c41896e..95824d5b64ce 100644
>> --- a/drivers/remoteproc/qcom_q6v5.h
>> +++ b/drivers/remoteproc/qcom_q6v5.h
>> @@ -7,6 +7,12 @@
>> #include <linux/completion.h>
>> #include <linux/soc/qcom/qcom_aoss.h>
>>
>> +#define RMB_BOOT_WAIT_REG 0x8
>> +#define RMB_BOOT_CONT_REG 0xC
>> +#define RMB_Q6_BOOT_STATUS_REG 0x10
>> +
>> +#define RMB_POLL_MAX_TIMES 250
>> +
>> struct icc_path;
>> struct rproc;
>> struct qcom_smem_state;
>> @@ -16,6 +22,8 @@ struct qcom_q6v5 {
>> struct device *dev;
>> struct rproc *rproc;
>>
>> + void __iomem *rmb_base;
>> +
>> struct qcom_smem_state *state;
>> struct qmp *qmp;
>>
>> --
>> 2.25.1
>>
On 3/15/2023 7:27 PM, Bjorn Andersson wrote:
> On Mon, Mar 06, 2023 at 03:12:01PM -0800, Melody Olvera wrote:
>> Some chipsets will have DSPs which will have begun running prior
>> to linux booting, so add support to late attach these DSPs by
>> adding support for:
>> - run-time checking of an offline or running DSP via rmb register
>> - a late attach framework to attach to the running DSP
>> - a handshake mechanism to ensure full and proper booting via rmb
>>
>> Signed-off-by: Melody Olvera <[email protected]>
>> ---
>> drivers/remoteproc/qcom_q6v5_pas.c | 103 ++++++++++++++++++++++++++++-
>> 1 file changed, 102 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
>> index 0871108fb4dc..e22be6a029a8 100644
>> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>> @@ -242,10 +242,89 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
>> return ret;
>> }
>>
>> +static int adsp_attach(struct rproc *rproc)
>> +{
>> + struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>> + int i, ret;
>> +
>> + ret = qcom_q6v5_prepare(&adsp->q6v5);
>> + if (ret)
>> + return ret;
>> +
>> + ret = adsp_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
>> + if (ret < 0)
>> + goto disable_irqs;
>> +
>> + ret = clk_prepare_enable(adsp->xo);
>> + if (ret)
>> + goto disable_proxy_pds;
>> +
>> + ret = clk_prepare_enable(adsp->aggre2_clk);
>> + if (ret)
>> + goto disable_xo_clk;
>> +
>> + if (adsp->cx_supply) {
>> + ret = regulator_enable(adsp->cx_supply);
>> + if (ret)
>> + goto disable_aggre2_clk;
>> + }
>> +
>> + if (adsp->px_supply) {
>> + ret = regulator_enable(adsp->px_supply);
>> + if (ret)
>> + goto disable_cx_supply;
>> + }
>> +
>> + /* if needed, signal Q6 to continute booting */
>> + if (adsp->q6v5.rmb_base) {
>> + for (i = 0; i < RMB_POLL_MAX_TIMES; i++) {
>> + if (readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
>> + writel_relaxed(1, adsp->q6v5.rmb_base + RMB_BOOT_CONT_REG);
>> + break;
>> + }
>> + msleep(20);
>> + }
>> +
>> + if (!readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
>> + dev_err(adsp->dev, "Didn't get rmb signal from %s\n", rproc->name);
>> + goto disable_px_supply;
>> + }
>> + }
>> +
>> + ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
>> + if (ret == -ETIMEDOUT) {
>> + dev_err(adsp->dev, "start timed out\n");
>> + qcom_scm_pas_shutdown(adsp->pas_id);
>> + goto disable_px_supply;
>> + }
>> +
>> + return 0;
>> +
>> +disable_px_supply:
>> + if (adsp->px_supply)
>> + regulator_disable(adsp->px_supply);
>> +disable_cx_supply:
>> + if (adsp->cx_supply)
>> + regulator_disable(adsp->cx_supply);
>> +disable_aggre2_clk:
>> + clk_disable_unprepare(adsp->aggre2_clk);
>> +disable_xo_clk:
>> + clk_disable_unprepare(adsp->xo);
>> +disable_proxy_pds:
>> + adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
>> +disable_irqs:
>> + qcom_q6v5_unprepare(&adsp->q6v5);
>> +
>> + /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
>> + adsp->firmware = NULL;
>> +
>> + return ret;
>> +}
>> +
>> static int adsp_start(struct rproc *rproc)
>> {
>> struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>> - int ret;
>> + int i, ret;
>>
>> ret = qcom_q6v5_prepare(&adsp->q6v5);
>> if (ret)
>> @@ -304,6 +383,22 @@ static int adsp_start(struct rproc *rproc)
>> goto release_pas_metadata;
>> }
>>
>> + /* if needed, signal Q6 to continute booting */
> Why does this come before the wait_for_start()? Is the DSP actually up
> and running when you hit attach, or is it just loaded?
Yeah so DSP is loaded and partially booted, but it's waiting for a signal from our driver
to complete the boot process through to err_ready.
>
>> + if (adsp->q6v5.rmb_base) {
> Afaict this is copy-paste from attach, please move it to a helper
> function.
Sure.
>
>> + for (i = 0; i < RMB_POLL_MAX_TIMES; i++) {
>> + if (readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
>> + writel_relaxed(1, adsp->q6v5.rmb_base + RMB_BOOT_CONT_REG);
>> + break;
>> + }
>> + msleep(20);
>> + }
>> +
>> + if (!readl_relaxed(adsp->q6v5.rmb_base + RMB_BOOT_WAIT_REG)) {
> If you hit the break above, there should be no reason to read this
> register again.
>
> Seems cleaner to write this as:
>
> ret = readl_poll_timeout();
> if (ret < 0)
> goto release;
>
> writel(1, ...);
That is much cleaner; I didn't know about the poll timeout function. Will rewrite using it.
Thanks,
Melody
>
> Regards,
> Bjorn
>
>> + dev_err(adsp->dev, "Didn't get rmb signal from %s\n", rproc->name);
>> + goto release_pas_metadata;
>> + }
>> + }
>> +
>> ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
>> if (ret == -ETIMEDOUT) {
>> dev_err(adsp->dev, "start timed out\n");
>> @@ -413,6 +508,7 @@ static unsigned long adsp_panic(struct rproc *rproc)
>> static const struct rproc_ops adsp_ops = {
>> .unprepare = adsp_unprepare,
>> .start = adsp_start,
>> + .attach = adsp_attach,
>> .stop = adsp_stop,
>> .da_to_va = adsp_da_to_va,
>> .parse_fw = qcom_register_dump_segments,
>> @@ -423,6 +519,7 @@ static const struct rproc_ops adsp_ops = {
>> static const struct rproc_ops adsp_minidump_ops = {
>> .unprepare = adsp_unprepare,
>> .start = adsp_start,
>> + .attach = adsp_attach,
>> .stop = adsp_stop,
>> .da_to_va = adsp_da_to_va,
>> .load = adsp_load,
>> @@ -728,6 +825,10 @@ static int adsp_probe(struct platform_device *pdev)
>> if (ret)
>> goto detach_proxy_pds;
>>
>> + if (adsp->q6v5.rmb_base &&
>> + readl_relaxed(adsp->q6v5.rmb_base + RMB_Q6_BOOT_STATUS_REG))
>> + rproc->state = RPROC_DETACHED;
>> +
>> qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
>> qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
>> adsp->sysmon = qcom_add_sysmon_subdev(rproc,
>> --
>> 2.25.1
>>
Thanks Bjorn for the review comments.
On 3/15/2023 7:12 PM, Bjorn Andersson wrote:
> On Mon, Mar 06, 2023 at 03:11:59PM -0800, Melody Olvera wrote:
>> From: Gokul Krishna Krishnakumar <[email protected]>
>>
>> When booting with split binaries, it may be that the offset of the first
>> program header lies inside the mdt's filesize, in this case the loader
>> would incorrectly assume that the bins were not split. The loading would
>> then continue on and fail for split bins.
>
> Can you please be more explicit about the scenario you're having
> problems with?
>
In this scenario below, the first pheader end address is < mdt file size
but the next pheader lies outside the mdt file size. The
_qcom_mdt_load() would continue on to load the firmware as a single
image which leads to load error. By checking if all the pheaders lie
inside the file size, we will be able to fix this issue.
fw = cdsp_dtb.mdt phdr->p_filesz = 148 phdr->p_offset 0 fw->size 4044
fw = cdsp_dtb.mdt phdr->p_filesz = 512 phdr->p_offset 148 fw->size 4044
fw = cdsp_dtb.mdt phdr->p_filesz = 3896 phdr->p_offset 4096 fw->size 4044
> Is the problem that the first segment is represented in both the .mdt
> and .b01, but different? Or is it that you find the hash in both .mdt
> abd .b01, but only one of them is valid?
>
>> This change updates the logic used
>> by the mdt loader to understand whether the firmware images are split or not
>> by checking if each programs header's segment lies within the file or not.
>>
>> Signed-off-by: Gokul Krishna Krishnakumar <[email protected]>
>> Signed-off-by: Melody Olvera <[email protected]>
>> ---
>> drivers/soc/qcom/mdt_loader.c | 64 +++++++++++++++++++----------------
>> 1 file changed, 35 insertions(+), 29 deletions(-)
>>
>> diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
>> index 33dd8c315eb7..3aadce299c02 100644
>> --- a/drivers/soc/qcom/mdt_loader.c
>> +++ b/drivers/soc/qcom/mdt_loader.c
>> @@ -31,6 +31,26 @@ static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
>> return true;
>> }
>>
>> +static bool qcom_mdt_bins_are_split(const struct firmware *fw)
>> +{
>> + const struct elf32_phdr *phdrs;
>> + const struct elf32_hdr *ehdr;
>> + uint64_t seg_start, seg_end;
>> + int i;
>> +
>> + ehdr = (struct elf32_hdr *)fw->data;
>> + phdrs = (struct elf32_phdr *)(ehdr + 1);
>> +
>> + for (i = 0; i < ehdr->e_phnum; i++) {
>> + seg_start = phdrs[i].p_offset;
>> + seg_end = phdrs[i].p_offset + phdrs[i].p_filesz;
>> + if (seg_start > fw->size || seg_end > fw->size)
>> + return true;
>> + }
>> +
>> + return false;
>> +}
>> +
>> static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
>> unsigned int segment, const char *fw_name,
>> struct device *dev)
>> @@ -167,23 +187,13 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
>> /* Copy ELF header */
>> memcpy(data, fw->data, ehdr_size);
>>
>
> The existing code handles 3 cases:
>
>> - if (ehdr_size + hash_size == fw->size) {
>
> 1) File is split, but hash resides with the ELF header in the .mdt
>
>> - /* Firmware is split and hash is packed following the ELF header */
>> - hash_offset = phdrs[0].p_filesz;
>> - memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
>> - } else if (phdrs[hash_segment].p_offset + hash_size <= fw->size) {
>
> 2) The hash segment exists in a segment of its own, but in the loaded
> image.
>
>> - /* Hash is in its own segment, but within the loaded file */
>> +
>> + if (qcom_mdt_bins_are_split(fw)) {
>> + ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
>> + } else {
>> hash_offset = phdrs[hash_segment].p_offset;
>> memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
>> - } else {
>
> 3) The image is split, and the hash segment resides in it's own file.
>
>
> Afaict the updated logic maintains #2 and #3, but drops #1. Please
> review the git history to see if you can determine which target this
> case exists with - and ask for someone to specifically verify your
> change there.
>
> Perhaps all your change is doing is removing case #1, in which case this
> should be clear in the commit message; and we need to validate that your
> new assumptions holds.
>
>> - /* Hash is in its own segment, beyond the loaded file */
>> - ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
>
> For some reason you reversed the condition and got this out of the else
> (seems like an unnecessary change)...but in the process you lost the
> error handling below.
>
Yes, Updating the patch to remove this unnecessary change in the
qcom_mdt_read_metadat().
>> - if (ret) {
>> - kfree(data);
>> - return ERR_PTR(ret);
>> - }
>> }
>> -
>> *data_len = ehdr_size + hash_size;
>>
>> return data;
>> @@ -270,6 +280,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
>> phys_addr_t min_addr = PHYS_ADDR_MAX;
>> ssize_t offset;
>> bool relocate = false;
>> + bool is_split;
>> void *ptr;
>> int ret = 0;
>> int i;
>> @@ -277,6 +288,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
>> if (!fw || !mem_region || !mem_phys || !mem_size)
>> return -EINVAL;
>>
>> + is_split = qcom_mdt_bins_are_split(fw);
>> ehdr = (struct elf32_hdr *)fw->data;
>> phdrs = (struct elf32_phdr *)(ehdr + 1);
>>
>> @@ -330,22 +342,16 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
>>
>> ptr = mem_region + offset;
>>
>> - if (phdr->p_filesz && phdr->p_offset < fw->size &&
>> - phdr->p_offset + phdr->p_filesz <= fw->size) {
>> - /* Firmware is large enough to be non-split */
>> - if (phdr->p_offset + phdr->p_filesz > fw->size) {
>> - dev_err(dev, "file %s segment %d would be truncated\n",
>> - fw_name, i);
>> - ret = -EINVAL;
>> - break;
>> + if (phdr->p_filesz) {
>
> If you just change the condition (phr->p_filesz && !issplit), then your
> patch becomes easier to read.
>
Done.
V3: only make change in the __qcom_mdt_load() and not in the
qcom_mdt_read_metadata().
> Regards,
> Bjorn
>
>> + if (!is_split) {
>> + /* Firmware is large enough to be non-split */
>> + memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
>> + } else {
>> + /* Firmware not large enough, load split-out segments */
>> + ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
>> + if (ret)
>> + break;
>> }
>> -
>> - memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
>> - } else if (phdr->p_filesz) {
>> - /* Firmware not large enough, load split-out segments */
>> - ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
>> - if (ret)
>> - break;
>> }
>>
>> if (phdr->p_memsz > phdr->p_filesz)
>> --
>> 2.25.1
>>
Thanks,
Gokul