diff options
| -rw-r--r-- | Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml | 3 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml | 1 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/remoteproc/qcom,shikra-pas.yaml | 167 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml | 4 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml | 4 | ||||
| -rw-r--r-- | drivers/firmware/xilinx/zynqmp.c | 28 | ||||
| -rw-r--r-- | drivers/remoteproc/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/remoteproc/imx_rproc.c | 95 | ||||
| -rw-r--r-- | drivers/remoteproc/imx_rproc.h | 2 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_common.c | 14 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_q6v5_pas.c | 51 | ||||
| -rw-r--r-- | drivers/remoteproc/qcom_q6v5_wcss.c | 23 | ||||
| -rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 81 | ||||
| -rw-r--r-- | drivers/remoteproc/xlnx_r5_remoteproc.c | 100 | ||||
| -rw-r--r-- | include/linux/firmware/xlnx-zynqmp.h | 21 | ||||
| -rw-r--r-- | include/linux/remoteproc.h | 269 | ||||
| -rw-r--r-- | include/linux/rsc_table.h | 359 |
17 files changed, 858 insertions, 367 deletions
diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml index ce8ec0119469..c18f71b64889 100644 --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml @@ -28,6 +28,9 @@ properties: - fsl,imx8qxp-cm4 - fsl,imx8ulp-cm33 - fsl,imx93-cm33 + - fsl,imx94-cm33s + - fsl,imx94-cm70 + - fsl,imx94-cm71 - fsl,imx95-cm7 clocks: diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml index 540bdfca53d9..823304afaa98 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml @@ -87,6 +87,7 @@ properties: - qcom,qcm2290-rpm-proc - qcom,qcs404-rpm-proc - qcom,sdm660-rpm-proc + - qcom,shikra-rpm-proc - qcom,sm6115-rpm-proc - qcom,sm6125-rpm-proc - qcom,sm6375-rpm-proc diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,shikra-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,shikra-pas.yaml new file mode 100644 index 000000000000..253b14eb2b59 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,shikra-pas.yaml @@ -0,0 +1,167 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,shikra-pas.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Shikra SoC Peripheral Authentication Service + +maintainers: + - Bibek Kumar Patro <bibek.patro@oss.qualcomm.com> + - Komal Bajaj <komal.bajaj@oss.qualcomm.com> + +description: + Qualcomm Shikra SoC Peripheral Authentication Service loads and boots + firmware on the Qualcomm DSP Hexagon cores. + +properties: + compatible: + enum: + - qcom,shikra-cdsp-pas + - qcom,shikra-lpaicp-pas + - qcom,shikra-mpss-pas + + reg: + maxItems: 1 + + clocks: + items: + - description: XO clock + + clock-names: + items: + - const: xo + + memory-region: + minItems: 1 + maxItems: 2 + + smd-edge: false + + firmware-name: + minItems: 1 + items: + - description: Firmware name of the Hexagon core + - description: Firmware name of the Hexagon Devicetree + + glink-edge: + $ref: /schemas/remoteproc/qcom,glink-edge.yaml# + description: + Qualcomm G-Link subnode which represents communication edge, channels + and devices related to the remoteproc core. + unevaluatedProperties: false + + qcom,smem-states: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: States used by the AP to signal the Hexagon core + items: + - description: Stop the remote processor + items: + - description: Phandle to the Shared Memory Point 2 Point device + handling the communication with a remote processor + - description: Single bit index to toggle in the value sent to + the remote processor + maximum: 32 + + qcom,smem-state-names: + description: The names of the state bits used for SMP2P output + items: + - const: stop + +required: + - compatible + - reg + - memory-region + +allOf: + - $ref: /schemas/remoteproc/qcom,pas-common.yaml# + + - if: + properties: + compatible: + enum: + - qcom,shikra-cdsp-pas + - qcom,shikra-mpss-pas + then: + properties: + interrupts: + minItems: 6 + interrupt-names: + minItems: 6 + memory-region: + maxItems: 1 + firmware-name: + maxItems: 1 + power-domains: + items: + - description: CX power domain + power-domain-names: + items: + - const: cx + + - if: + properties: + compatible: + enum: + - qcom,shikra-lpaicp-pas + then: + properties: + interrupts: + maxItems: 5 + interrupt-names: + maxItems: 5 + memory-region: + minItems: 2 + firmware-name: + minItems: 2 + power-domains: false + power-domain-names: false + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/qcom,rpmcc.h> + #include <dt-bindings/interconnect/qcom,icc.h> + #include <dt-bindings/interconnect/qcom,rpm-icc.h> + #include <dt-bindings/interconnect/qcom,shikra.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/power/qcom-rpmpd.h> + + remoteproc@b300000 { + compatible = "qcom,shikra-cdsp-pas"; + reg = <0x0b300000 0x100000>; + + interrupts-extended = <&intc GIC_SPI 265 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack", "shutdown-ack"; + + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "xo"; + + interconnects = <&mem_noc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &mc_virt SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + + power-domains = <&rpmpd RPMHPD_CX>; + power-domain-names = "cx"; + + memory-region = <&cdsp_mem>; + + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + firmware-name = "qcom/shikra/cdsp.mbn"; + + glink-edge { + interrupts = <GIC_SPI 261 IRQ_TYPE_EDGE_RISING>; + mboxes = <&apcs_glb 4>; + qcom,remote-pid = <5>; + label = "cdsp"; + }; + }; diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml index 1e4db0c9fcf9..9f30a38152a3 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml @@ -30,12 +30,14 @@ properties: - items: - enum: - qcom,glymur-adsp-pas + - qcom,hawi-adsp-pas - qcom,kaanapali-adsp-pas - qcom,sm8750-adsp-pas - const: qcom,sm8550-adsp-pas - items: - enum: - qcom,glymur-cdsp-pas + - qcom,hawi-cdsp-pas - qcom,kaanapali-cdsp-pas - const: qcom,sm8550-cdsp-pas - items: @@ -104,6 +106,8 @@ allOf: enum: - qcom,glymur-adsp-pas - qcom,glymur-cdsp-pas + - qcom,hawi-adsp-pas + - qcom,hawi-cdsp-pas - qcom,kaanapali-adsp-pas - qcom,kaanapali-cdsp-pas - qcom,sm8750-adsp-pas diff --git a/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml b/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml index c7d5e58330d6..5ab19d70a344 100644 --- a/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml +++ b/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml @@ -128,6 +128,10 @@ patternProperties: - description: vring1 additionalItems: true + firmware-name: + maxItems: 1 + description: default firmware to load + required: - compatible - reg diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index fbe8510f4927..af838b2dc327 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -1451,6 +1451,34 @@ int zynqmp_pm_get_node_status(const u32 node, u32 *const status, EXPORT_SYMBOL_GPL(zynqmp_pm_get_node_status); /** + * zynqmp_pm_get_rpu_node_status - PM call to request a RPU node's current power state + * @node: ID of the RPU component or sub-system in question + * @status: Current operating state of the requested RPU node. + * @requirements: Current requirements asserted on the RPU node. + * @usage: Usage information, used for RPU slave nodes only: + * PM_USAGE_NO_MASTER - No master is currently using + * the node + * PM_USAGE_CURRENT_MASTER - Only requesting master is + * currently using the node + * PM_USAGE_OTHER_MASTER - Only other masters are + * currently using the node + * PM_USAGE_BOTH_MASTERS - Both the current and at least + * one other master is currently + * using the node + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status, + u32 *const requirements, u32 *const usage) +{ + if (zynqmp_pm_feature(PM_GET_NODE_STATUS) < PM_API_VERSION_2) + return -EOPNOTSUPP; + + return zynqmp_pm_get_node_status(node, status, requirements, usage); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_node_status); + +/** * zynqmp_pm_force_pwrdwn - PM call to request for another PU or subsystem to * be powered down forcefully * @node: Node ID of the targeted PU or subsystem diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index ee54436fea5a..c521c744e7db 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -176,7 +176,7 @@ config QCOM_Q6V5_COMMON depends on QCOM_SMEM config QCOM_Q6V5_ADSP - tristate "Qualcomm Technology Inc ADSP Peripheral Image Loader" + tristate "Qualcomm ADSP Peripheral Image Loader" depends on OF && ARCH_QCOM depends on QCOM_SMEM depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n @@ -316,7 +316,6 @@ config ST_SLIM_REMOTEPROC config STM32_RPROC tristate "STM32 remoteproc support" depends on ARCH_STM32 || COMPILE_TEST - depends on REMOTEPROC select MAILBOX help Say y here to support STM32 MCU processors via the diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 0dd80e688b0e..7662ebd9d2f4 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -145,6 +145,41 @@ static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = { { 0x80000000, 0x80000000, 0x50000000, 0 }, }; +static const struct imx_rproc_att imx_rproc_att_imx94_m70[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* TCM SYS NON-SECURE*/ + { 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x10000000, 0 }, +}; + +static const struct imx_rproc_att imx_rproc_att_imx94_m71[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x00000000, 0x202C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* TCM SYS NON-SECURE*/ + { 0x20000000, 0x20300000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x10000000, 0 }, +}; + +static const struct imx_rproc_att imx_rproc_att_imx94_m33s[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x0FFC0000, 0x209C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* TCM SYS NON-SECURE */ + { 0x20000000, 0x20A00000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* M33S OCRAM NON-SECURE */ + { 0x20800000, 0x20800000, 0x180000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x10000000, 0 }, +}; + static const struct imx_rproc_att imx_rproc_att_imx93[] = { /* dev addr , sys addr , size , flags */ /* TCM CODE NON-SECURE */ @@ -339,13 +374,32 @@ static int imx_rproc_scu_api_start(struct rproc *rproc) return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); } +static u64 imx_rproc_sm_get_reset_vector(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + u32 reset_vector_mask = priv->dcfg->reset_vector_mask ?: GENMASK(31, 0); + + /* + * The hardware fetches the first two words from reset_vectors + * (hardware reset address) and populates SP and PC using the first + * two words. Execution proceeds from PC. The ELF entry point does + * not always match the hardware reset address. + * To derive the correct hardware reset address, the lower address + * bits must be masked off before programming the reset vector. + */ + return rproc->bootaddr & reset_vector_mask; +} + static int imx_rproc_sm_cpu_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; + u64 reset_vector; int ret; - ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false); + reset_vector = imx_rproc_sm_get_reset_vector(rproc); + + ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, reset_vector, true, false, false); if (ret) { dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret); return ret; @@ -359,13 +413,16 @@ static int imx_rproc_sm_lmm_start(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + u64 reset_vector; int ret; + reset_vector = imx_rproc_sm_get_reset_vector(rproc); + /* * If the remoteproc core can't start the M7, it will already be * handled in imx_rproc_sm_lmm_prepare(). */ - ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0); + ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, reset_vector); if (ret) { dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n", dcfg->lmid, dcfg->cpuid, ret); @@ -1230,8 +1287,7 @@ static int imx_rproc_probe(struct platform_device *pdev) const struct imx_rproc_dcfg *dcfg; int ret; - /* set some other name then imx */ - rproc = devm_rproc_alloc(dev, "imx-rproc", &imx_rproc_ops, + rproc = devm_rproc_alloc(dev, np->name, &imx_rproc_ops, NULL, sizeof(*priv)); if (!rproc) return -ENOMEM; @@ -1455,6 +1511,33 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { .flags = IMX_RPROC_NEED_CLKS, }; +static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m70 = { + .att = imx_rproc_att_imx94_m70, + .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m70), + .ops = &imx_rproc_ops_sm_lmm, + .cpuid = 1, + .lmid = 2, + .reset_vector_mask = GENMASK_U32(31, 16), +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m71 = { + .att = imx_rproc_att_imx94_m71, + .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m71), + .ops = &imx_rproc_ops_sm_lmm, + .cpuid = 7, + .lmid = 3, + .reset_vector_mask = GENMASK_U32(31, 16), +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m33s = { + .att = imx_rproc_att_imx94_m33s, + .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m33s), + .ops = &imx_rproc_ops_sm_lmm, + .cpuid = 8, + .lmid = 1, + .reset_vector_mask = GENMASK_U32(31, 16), +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { .att = imx_rproc_att_imx95_m7, .att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7), @@ -1462,6 +1545,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { /* Must align with System Manager Firmware */ .cpuid = 1, /* Use 1 as cpu id for M7 core */ .lmid = 1, /* Use 1 as Logical Machine ID where M7 resides */ + .reset_vector_mask = GENMASK_U32(31, 16), }; static const struct of_device_id imx_rproc_of_match[] = { @@ -1478,6 +1562,9 @@ static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm }, { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, { .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 }, + { .compatible = "fsl,imx94-cm70", .data = &imx_rproc_cfg_imx94_m70 }, + { .compatible = "fsl,imx94-cm71", .data = &imx_rproc_cfg_imx94_m71 }, + { .compatible = "fsl,imx94-cm33s", .data = &imx_rproc_cfg_imx94_m33s }, { .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 }, {}, }; diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index d37e6f90548c..0d7d48352a10 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -41,6 +41,8 @@ struct imx_rproc_dcfg { /* For System Manager(SM) based SoCs */ u32 cpuid; /* ID of the remote core */ u32 lmid; /* ID of the Logcial Machine */ + /* reset_vector = elf_entry_addr & reset_vector_mask */ + u32 reset_vector_mask; }; #endif /* _IMX_RPROC_H */ diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index fd2b6824ad26..e1a955476c9b 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -109,6 +109,7 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy struct minidump_region __iomem *ptr; struct minidump_region region; int seg_cnt, i; + int ret = 0; dma_addr_t da; size_t size; char *name; @@ -129,17 +130,22 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy if (le32_to_cpu(region.valid) == MINIDUMP_REGION_VALID) { name = kstrndup(region.name, MAX_REGION_NAME_LENGTH - 1, GFP_KERNEL); if (!name) { - iounmap(ptr); - return -ENOMEM; + ret = -ENOMEM; + break; } da = le64_to_cpu(region.address); size = le64_to_cpu(region.size); - rproc_coredump_add_custom_segment(rproc, da, size, rproc_dumpfn_t, name); + ret = rproc_coredump_add_custom_segment(rproc, da, size, rproc_dumpfn_t, + name); + if (ret) { + kfree(name); + break; + } } } iounmap(ptr); - return 0; + return ret; } void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index da27d1d3c9da..808e9609988d 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -92,9 +92,6 @@ struct qcom_pas { const struct firmware *firmware; const struct firmware *dtb_firmware; - struct completion start_done; - struct completion stop_done; - phys_addr_t mem_phys; phys_addr_t dtb_mem_phys; phys_addr_t mem_reloc; @@ -1457,6 +1454,51 @@ static const struct qcom_pas_data sc7280_wpss_resource = { .ssctl_id = 0x19, }; +static const struct qcom_pas_data shikra_cdsp_resource = { + .crash_reason_smem = 601, + .firmware_name = "cdsp.mbn", + .pas_id = 18, + .minidump_id = 7, + .auto_boot = true, + .proxy_pd_names = (char *[]){ + "cx", + NULL + }, + .load_state = "cdsp", + .ssr_name = "cdsp", + .sysmon_name = "cdsp", + .ssctl_id = 0x17, + .smem_host_id = 5, +}; + +static const struct qcom_pas_data shikra_lpaicp_resource = { + .crash_reason_smem = 682, + .firmware_name = "lpaicp.mbn", + .dtb_firmware_name = "lpaicp_dtb.mbn", + .pas_id = 0x56, + .dtb_pas_id = 0x57, + .minidump_id = 0, + .auto_boot = true, + .ssr_name = "lpaicp", + .sysmon_name = "lpaicp", +}; + +static const struct qcom_pas_data shikra_mpss_resource = { + .crash_reason_smem = 421, + .firmware_name = "qdsp6sw.mbn", + .pas_id = 4, + .minidump_id = 3, + .auto_boot = false, + .proxy_pd_names = (char *[]){ + "cx", + NULL + }, + .load_state = "modem", + .ssr_name = "mpss", + .sysmon_name = "modem", + .ssctl_id = 0x12, +}; + static const struct qcom_pas_data sm8650_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", @@ -1571,6 +1613,9 @@ static const struct of_device_id qcom_pas_of_match[] = { { .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init }, { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource }, { .compatible = "qcom,sdx75-mpss-pas", .data = &sm8650_mpss_resource }, + { .compatible = "qcom,shikra-cdsp-pas", .data = &shikra_cdsp_resource }, + { .compatible = "qcom,shikra-lpaicp-pas", .data = &shikra_lpaicp_resource }, + { .compatible = "qcom,shikra-mpss-pas", .data = &shikra_mpss_resource }, { .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init }, { .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource }, diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index c27200159a88..b391724cfd08 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -96,7 +96,6 @@ struct wcss_data { unsigned int crash_reason_smem; u32 version; bool aon_reset_required; - bool wcss_q6_reset_required; const char *ssr_name; const char *sysmon_name; int ssctl_id; @@ -134,7 +133,6 @@ struct q6v5_wcss { struct reset_control *wcss_aon_reset; struct reset_control *wcss_reset; struct reset_control *wcss_q6_reset; - struct reset_control *wcss_q6_bcr_reset; struct qcom_q6v5 q6v5; @@ -309,7 +307,7 @@ static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss) return ret; /* Remove reset to the WCNSS QDSP6SS */ - reset_control_deassert(wcss->wcss_q6_bcr_reset); + reset_control_deassert(wcss->wcss_q6_reset); /* Enable Q6SSTOP_AHBFABRIC_CBCR clock */ ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk); @@ -803,19 +801,10 @@ static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss, return PTR_ERR(wcss->wcss_reset); } - if (desc->wcss_q6_reset_required) { - wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset"); - if (IS_ERR(wcss->wcss_q6_reset)) { - dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); - return PTR_ERR(wcss->wcss_q6_reset); - } - } - - wcss->wcss_q6_bcr_reset = devm_reset_control_get_optional_exclusive(dev, - "wcss_q6_bcr_reset"); - if (IS_ERR(wcss->wcss_q6_bcr_reset)) { - dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n"); - return PTR_ERR(wcss->wcss_q6_bcr_reset); + wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset"); + if (IS_ERR(wcss->wcss_q6_reset)) { + dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); + return PTR_ERR(wcss->wcss_q6_reset); } return 0; @@ -1062,7 +1051,6 @@ static const struct wcss_data wcss_ipq8074_res_init = { .firmware_name = "IPQ8074/q6_fw.mdt", .crash_reason_smem = WCSS_CRASH_REASON, .aon_reset_required = true, - .wcss_q6_reset_required = true, .ops = &q6v5_wcss_ipq8074_ops, .requires_force_stop = true, }; @@ -1072,7 +1060,6 @@ static const struct wcss_data wcss_qcs404_res_init = { .firmware_name = "wcnss.mdt", .version = WCSS_QCS404, .aon_reset_required = false, - .wcss_q6_reset_required = false, .ssr_name = "mpss", .sysmon_name = "wcnss", .ssctl_id = 0x12, diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index b087ed21858a..f003be006b1b 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1011,60 +1011,55 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { [RSC_VDEV] = rproc_handle_vdev, }; -/* handle firmware resource entries before booting the remote processor */ -static int rproc_handle_resources(struct rproc *rproc, - rproc_handle_resource_t handlers[RSC_LAST]) +struct rproc_rsc_cb_data { + struct rproc *rproc; + rproc_handle_resource_t *handlers; +}; + +static int rproc_handle_rsc_entry(u32 type, void *rsc, int offset, + int avail, void *data) { + struct rproc_rsc_cb_data *d = data; + struct rproc *rproc = d->rproc; struct device *dev = &rproc->dev; rproc_handle_resource_t handler; - int ret = 0, i; - - if (!rproc->table_ptr) - return 0; + int ret; - for (i = 0; i < rproc->table_ptr->num; i++) { - int offset = rproc->table_ptr->offset[i]; - struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset; - int avail = rproc->table_sz - offset - sizeof(*hdr); - void *rsc = (void *)hdr + sizeof(*hdr); + dev_dbg(dev, "rsc: type %d\n", type); - /* make sure table isn't truncated */ - if (avail < 0) { - dev_err(dev, "rsc table is truncated\n"); - return -EINVAL; - } - - dev_dbg(dev, "rsc: type %d\n", hdr->type); + if (type >= RSC_VENDOR_START && type <= RSC_VENDOR_END) { + ret = rproc_handle_rsc(rproc, type, rsc, offset, avail); + if (ret == RSC_HANDLED) + return 0; + if (ret < 0) + return ret; + dev_warn(dev, "unsupported vendor resource %d\n", type); + return 0; + } - if (hdr->type >= RSC_VENDOR_START && - hdr->type <= RSC_VENDOR_END) { - ret = rproc_handle_rsc(rproc, hdr->type, rsc, - offset + sizeof(*hdr), avail); - if (ret == RSC_HANDLED) - continue; - else if (ret < 0) - break; + if (type >= RSC_LAST) { + dev_warn(dev, "unsupported resource %d\n", type); + return 0; + } - dev_warn(dev, "unsupported vendor resource %d\n", - hdr->type); - continue; - } + handler = d->handlers[type]; + if (!handler) + return 0; - if (hdr->type >= RSC_LAST) { - dev_warn(dev, "unsupported resource %d\n", hdr->type); - continue; - } + return handler(rproc, rsc, offset, avail); +} - handler = handlers[hdr->type]; - if (!handler) - continue; +/* handle firmware resource entries before booting the remote processor */ +static int rproc_handle_resources(struct rproc *rproc, + rproc_handle_resource_t handlers[RSC_LAST]) +{ + struct rproc_rsc_cb_data d = { .rproc = rproc, .handlers = handlers }; - ret = handler(rproc, rsc, offset + sizeof(*hdr), avail); - if (ret) - break; - } + if (!rproc->table_ptr) + return 0; - return ret; + return rsc_table_for_each_entry(rproc->table_ptr, rproc->table_sz, + &rproc->dev, rproc_handle_rsc_entry, &d); } static int rproc_prepare_subdevices(struct rproc *rproc) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index 50a9974f3202..3349d1877751 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -4,7 +4,6 @@ * */ -#include <dt-bindings/power/xlnx-zynqmp-power.h> #include <linux/dma-mapping.h> #include <linux/firmware/xlnx-zynqmp.h> #include <linux/kernel.h> @@ -19,6 +18,11 @@ #include "remoteproc_internal.h" +#define PD_R5_0_ATCM 15 +#define PD_R5_0_BTCM 16 +#define PD_R5_1_ATCM 17 +#define PD_R5_1_BTCM 18 + /* IPI buffer MAX length */ #define IPI_BUF_LEN_MAX 32U @@ -899,17 +903,18 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = { }; /** - * zynqmp_r5_add_rproc_core() - Add core data to framework. - * Allocate and add struct rproc object for each r5f core + * zynqmp_r5_alloc_rproc_core() - alloc rproc core data structure + * Allocate struct rproc object for each r5f core * This is called for each individual r5f core * * @cdev: Device node of each r5 core * * Return: zynqmp_r5_core object for success else error code pointer */ -static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) +static struct zynqmp_r5_core *zynqmp_r5_alloc_rproc_core(struct device *cdev) { struct zynqmp_r5_core *r5_core; + const char *fw_name = NULL; struct rproc *r5_rproc; int ret; @@ -918,10 +923,15 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) if (ret) return ERR_PTR(ret); + ret = rproc_of_parse_firmware(cdev, 0, &fw_name); + if (ret < 0 && ret != -EINVAL) + return ERR_PTR(dev_err_probe(cdev, ret, + "failed to parse firmware-name\n")); + /* Allocate remoteproc instance */ r5_rproc = rproc_alloc(cdev, dev_name(cdev), &zynqmp_r5_rproc_ops, - NULL, sizeof(struct zynqmp_r5_core)); + fw_name, sizeof(struct zynqmp_r5_core)); if (!r5_rproc) { dev_err(cdev, "failed to allocate memory for rproc instance\n"); return ERR_PTR(-ENOMEM); @@ -932,6 +942,11 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) r5_rproc->recovery_disabled = true; r5_rproc->has_iommu = false; r5_rproc->auto_boot = false; + + /* attempt to boot automatically if the firmware-name is provided */ + if (fw_name) + r5_rproc->auto_boot = true; + r5_core = r5_rproc->priv; r5_core->dev = cdev; r5_core->np = dev_of_node(cdev); @@ -941,23 +956,6 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) goto free_rproc; } - /* Add R5 remoteproc core */ - ret = rproc_add(r5_rproc); - if (ret) { - dev_err(cdev, "failed to add r5 remoteproc\n"); - goto free_rproc; - } - - /* - * If firmware is already available in the memory then move rproc state - * to DETACHED. Firmware can be preloaded via debugger or by any other - * agent (processors) in the system. - * If firmware isn't available in the memory and resource table isn't - * found, then rproc state remains OFFLINE. - */ - if (!zynqmp_r5_get_rsc_table_va(r5_core)) - r5_rproc->state = RPROC_DETACHED; - r5_core->rproc = r5_rproc; return r5_core; @@ -1210,6 +1208,7 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, { struct device *dev = cluster->dev; struct zynqmp_r5_core *r5_core; + u32 req, usage, status; int ret = -EINVAL, i; r5_core = cluster->r5_cores[0]; @@ -1255,6 +1254,42 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, ret = zynqmp_r5_get_sram_banks(r5_core); if (ret) return ret; + + /* + * It is possible that firmware is loaded into the memory, but + * RPU (remote) is not running. In such case, RPU state will be + * moved to RPROC_DETACHED wrongfully. To avoid it first make + * sure RPU is power-on and out of reset before parsing for the + * resource table. + */ + ret = zynqmp_pm_get_rpu_node_status(r5_core->pm_domain_id, + &status, &req, &usage); + if (ret) { + dev_warn(r5_core->dev, + "failed to get rpu node status, err %d\n", ret); + continue; + } + + /* + * If RPU state is power on and out of reset i.e. running, then + * assign RPROC_DETACHED state. If the RPU is not out of reset + * then do not attempt to attach to the remote processor. + */ + if (status == PM_NODE_RUNNING) { + /* + * Not all the firmware that is running on the remote + * core is expected to have the resource table. The + * firmware might not use RPMsg at all, and in that case + * resource table becomes irrelevant. However, we still + * need to make sure that running core is not reported + * as offline. so do not decide remote core state based + * on the resource table availability + */ + if (zynqmp_r5_get_rsc_table_va(r5_core)) + dev_dbg(r5_core->dev, "rsc tbl not found\n"); + r5_core->rproc->state = RPROC_DETACHED; + r5_core->rproc->auto_boot = true; + } } return 0; @@ -1278,7 +1313,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) enum rpu_oper_mode fw_reg_val; struct device **child_devs; enum rpu_tcm_comb tcm_mode; - int core_count, ret, i; + int core_count, ret, i, j; struct mbox_info *ipi; ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode); @@ -1364,7 +1399,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) child_devs[i] = &child_pdev->dev; /* create and add remoteproc instance of type struct rproc */ - r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev); + r5_cores[i] = zynqmp_r5_alloc_rproc_core(&child_pdev->dev); if (IS_ERR(r5_cores[i])) { ret = PTR_ERR(r5_cores[i]); r5_cores[i] = NULL; @@ -1409,16 +1444,31 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) goto release_r5_cores; } + for (j = 0; j < cluster->core_count; j++) { + /* Add R5 remoteproc core */ + ret = rproc_add(r5_cores[j]->rproc); + if (ret) { + dev_err_probe(r5_cores[j]->dev, ret, + "failed to add remoteproc\n"); + goto delete_r5_cores; + } + } + kfree(child_devs); return 0; +delete_r5_cores: + i = core_count - 1; + /* delete previous added rproc */ + while (--j >= 0) + rproc_del(r5_cores[j]->rproc); + release_r5_cores: while (i >= 0) { put_device(child_devs[i]); if (r5_cores[i]) { zynqmp_r5_free_mbox(r5_cores[i]->ipi); of_reserved_mem_device_release(r5_cores[i]->dev); - rproc_del(r5_cores[i]->rproc); rproc_free(r5_cores[i]->rproc); } i--; diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index d70dcd462b44..7e27b0f7bf7e 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -543,6 +543,18 @@ enum pm_gem_config_type { }; /** + * enum pm_node_status - Device node status provided by xilpm fw + * @PM_NODE_UNUSED: Device is not used + * @PM_NODE_RUNNING: Device is power-on and out of reset + * @PM_NODE_HALT: Device is power-on but in the reset state + */ +enum pm_node_status { + PM_NODE_UNUSED = 0, + PM_NODE_RUNNING = 1, + PM_NODE_HALT = 12, +}; + +/** * struct zynqmp_pm_query_data - PM query data * @qid: query ID * @arg1: Argument 1 of query data @@ -630,6 +642,8 @@ int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode); int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode); int zynqmp_pm_get_node_status(const u32 node, u32 *const status, u32 *const requirements, u32 *const usage); +int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status, + u32 *const requirements, u32 *const usage); int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value); @@ -939,6 +953,13 @@ static inline int zynqmp_pm_get_node_status(const u32 node, u32 *const status, return -ENODEV; } +static inline int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status, + u32 *const requirements, + u32 *const usage) +{ + return -ENODEV; +} + static inline int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value) diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index b4795698d8c2..7c1546d48008 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -42,274 +42,7 @@ #include <linux/completion.h> #include <linux/idr.h> #include <linux/of.h> - -/** - * struct resource_table - firmware resource table header - * @ver: version number - * @num: number of resource entries - * @reserved: reserved (must be zero) - * @offset: array of offsets pointing at the various resource entries - * - * A resource table is essentially a list of system resources required - * by the remote processor. It may also include configuration entries. - * If needed, the remote processor firmware should contain this table - * as a dedicated ".resource_table" ELF section. - * - * Some resources entries are mere announcements, where the host is informed - * of specific remoteproc configuration. Other entries require the host to - * do something (e.g. allocate a system resource). Sometimes a negotiation - * is expected, where the firmware requests a resource, and once allocated, - * the host should provide back its details (e.g. address of an allocated - * memory region). - * - * The header of the resource table, as expressed by this structure, - * contains a version number (should we need to change this format in the - * future), the number of available resource entries, and their offsets - * in the table. - * - * Immediately following this header are the resource entries themselves, - * each of which begins with a resource entry header (as described below). - */ -struct resource_table { - u32 ver; - u32 num; - u32 reserved[2]; - u32 offset[]; -} __packed; - -/** - * struct fw_rsc_hdr - firmware resource entry header - * @type: resource type - * @data: resource data - * - * Every resource entry begins with a 'struct fw_rsc_hdr' header providing - * its @type. The content of the entry itself will immediately follow - * this header, and it should be parsed according to the resource type. - */ -struct fw_rsc_hdr { - u32 type; - u8 data[]; -} __packed; - -/** - * enum fw_resource_type - types of resource entries - * - * @RSC_CARVEOUT: request for allocation of a physically contiguous - * memory region. - * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. - * @RSC_TRACE: announces the availability of a trace buffer into which - * the remote processor will be writing logs. - * @RSC_VDEV: declare support for a virtio device, and serve as its - * virtio header. - * @RSC_LAST: just keep this one at the end of standard resources - * @RSC_VENDOR_START: start of the vendor specific resource types range - * @RSC_VENDOR_END: end of the vendor specific resource types range - * - * For more details regarding a specific resource type, please see its - * dedicated structure below. - * - * Please note that these values are used as indices to the rproc_handle_rsc - * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to - * check the validity of an index before the lookup table is accessed, so - * please update it as needed. - */ -enum fw_resource_type { - RSC_CARVEOUT = 0, - RSC_DEVMEM = 1, - RSC_TRACE = 2, - RSC_VDEV = 3, - RSC_LAST = 4, - RSC_VENDOR_START = 128, - RSC_VENDOR_END = 512, -}; - -#define FW_RSC_ADDR_ANY (-1) - -/** - * struct fw_rsc_carveout - physically contiguous memory request - * @da: device address - * @pa: physical address - * @len: length (in bytes) - * @flags: iommu protection flags - * @reserved: reserved (must be zero) - * @name: human-readable name of the requested memory region - * - * This resource entry requests the host to allocate a physically contiguous - * memory region. - * - * These request entries should precede other firmware resource entries, - * as other entries might request placing other data objects inside - * these memory regions (e.g. data/code segments, trace resource entries, ...). - * - * Allocating memory this way helps utilizing the reserved physical memory - * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries - * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB - * pressure is important; it may have a substantial impact on performance. - * - * If the firmware is compiled with static addresses, then @da should specify - * the expected device address of this memory region. If @da is set to - * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then - * overwrite @da with the dynamically allocated address. - * - * We will always use @da to negotiate the device addresses, even if it - * isn't using an iommu. In that case, though, it will obviously contain - * physical addresses. - * - * Some remote processors needs to know the allocated physical address - * even if they do use an iommu. This is needed, e.g., if they control - * hardware accelerators which access the physical memory directly (this - * is the case with OMAP4 for instance). In that case, the host will - * overwrite @pa with the dynamically allocated physical address. - * Generally we don't want to expose physical addresses if we don't have to - * (remote processors are generally _not_ trusted), so we might want to - * change this to happen _only_ when explicitly required by the hardware. - * - * @flags is used to provide IOMMU protection flags, and @name should - * (optionally) contain a human readable name of this carveout region - * (mainly for debugging purposes). - */ -struct fw_rsc_carveout { - u32 da; - u32 pa; - u32 len; - u32 flags; - u32 reserved; - u8 name[32]; -} __packed; - -/** - * struct fw_rsc_devmem - iommu mapping request - * @da: device address - * @pa: physical address - * @len: length (in bytes) - * @flags: iommu protection flags - * @reserved: reserved (must be zero) - * @name: human-readable name of the requested region to be mapped - * - * This resource entry requests the host to iommu map a physically contiguous - * memory region. This is needed in case the remote processor requires - * access to certain memory-based peripherals; _never_ use it to access - * regular memory. - * - * This is obviously only needed if the remote processor is accessing memory - * via an iommu. - * - * @da should specify the required device address, @pa should specify - * the physical address we want to map, @len should specify the size of - * the mapping and @flags is the IOMMU protection flags. As always, @name may - * (optionally) contain a human readable name of this mapping (mainly for - * debugging purposes). - * - * Note: at this point we just "trust" those devmem entries to contain valid - * physical addresses, but this isn't safe and will be changed: eventually we - * want remoteproc implementations to provide us ranges of physical addresses - * the firmware is allowed to request, and not allow firmwares to request - * access to physical addresses that are outside those ranges. - */ -struct fw_rsc_devmem { - u32 da; - u32 pa; - u32 len; - u32 flags; - u32 reserved; - u8 name[32]; -} __packed; - -/** - * struct fw_rsc_trace - trace buffer declaration - * @da: device address - * @len: length (in bytes) - * @reserved: reserved (must be zero) - * @name: human-readable name of the trace buffer - * - * This resource entry provides the host information about a trace buffer - * into which the remote processor will write log messages. - * - * @da specifies the device address of the buffer, @len specifies - * its size, and @name may contain a human readable name of the trace buffer. - * - * After booting the remote processor, the trace buffers are exposed to the - * user via debugfs entries (called trace0, trace1, etc..). - */ -struct fw_rsc_trace { - u32 da; - u32 len; - u32 reserved; - u8 name[32]; -} __packed; - -/** - * struct fw_rsc_vdev_vring - vring descriptor entry - * @da: device address - * @align: the alignment between the consumer and producer parts of the vring - * @num: num of buffers supported by this vring (must be power of two) - * @notifyid: a unique rproc-wide notify index for this vring. This notify - * index is used when kicking a remote processor, to let it know that this - * vring is triggered. - * @pa: physical address - * - * This descriptor is not a resource entry by itself; it is part of the - * vdev resource type (see below). - * - * Note that @da should either contain the device address where - * the remote processor is expecting the vring, or indicate that - * dynamically allocation of the vring's device address is supported. - */ -struct fw_rsc_vdev_vring { - u32 da; - u32 align; - u32 num; - u32 notifyid; - u32 pa; -} __packed; - -/** - * struct fw_rsc_vdev - virtio device header - * @id: virtio device id (as in virtio_ids.h) - * @notifyid: a unique rproc-wide notify index for this vdev. This notify - * index is used when kicking a remote processor, to let it know that the - * status/features of this vdev have changes. - * @dfeatures: specifies the virtio device features supported by the firmware - * @gfeatures: a place holder used by the host to write back the - * negotiated features that are supported by both sides. - * @config_len: the size of the virtio config space of this vdev. The config - * space lies in the resource table immediate after this vdev header. - * @status: a place holder where the host will indicate its virtio progress. - * @num_of_vrings: indicates how many vrings are described in this vdev header - * @reserved: reserved (must be zero) - * @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. - * - * This resource is a virtio device header: it provides information about - * the vdev, and is then used by the host and its peer remote processors - * to negotiate and share certain virtio properties. - * - * By providing this resource entry, the firmware essentially asks remoteproc - * to statically allocate a vdev upon registration of the rproc (dynamic vdev - * allocation is not yet supported). - * - * Note: - * 1. unlike virtualization systems, the term 'host' here means - * the Linux side which is running remoteproc to control the remote - * processors. We use the name 'gfeatures' to comply with virtio's terms, - * though there isn't really any virtualized guest OS here: it's the host - * which is responsible for negotiating the final features. - * Yeah, it's a bit confusing. - * - * 2. immediately following this structure is the virtio config space for - * this vdev (which is specific to the vdev; for more info, read the virtio - * spec). The size of the config space is specified by @config_len. - */ -struct fw_rsc_vdev { - u32 id; - u32 notifyid; - u32 dfeatures; - u32 gfeatures; - u32 config_len; - u8 status; - u8 num_of_vrings; - u8 reserved[2]; - struct fw_rsc_vdev_vring vring[]; -} __packed; +#include <linux/rsc_table.h> struct rproc; diff --git a/include/linux/rsc_table.h b/include/linux/rsc_table.h new file mode 100644 index 000000000000..c6d6d553d8f1 --- /dev/null +++ b/include/linux/rsc_table.h @@ -0,0 +1,359 @@ +/* + * Resource table and its types data structure + * + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Texas Instruments nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RSC_TABLE_H +#define RSC_TABLE_H + +/** + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries + * + * A resource table is essentially a list of system resources required + * by the remote processor. It may also include configuration entries. + * If needed, the remote processor firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * Some resources entries are mere announcements, where the host is informed + * of specific remoteproc configuration. Other entries require the host to + * do something (e.g. allocate a system resource). Sometimes a negotiation + * is expected, where the firmware requests a resource, and once allocated, + * the host should provide back its details (e.g. address of an allocated + * memory region). + * + * The header of the resource table, as expressed by this structure, + * contains a version number (should we need to change this format in the + * future), the number of available resource entries, and their offsets + * in the table. + * + * Immediately following this header are the resource entries themselves, + * each of which begins with a resource entry header (as described below). + */ +struct resource_table { + u32 ver; + u32 num; + u32 reserved[2]; + u32 offset[]; +} __packed; + +/** + * struct fw_rsc_hdr - firmware resource entry header + * @type: resource type + * @data: resource data + * + * Every resource entry begins with a 'struct fw_rsc_hdr' header providing + * its @type. The content of the entry itself will immediately follow + * this header, and it should be parsed according to the resource type. + */ +struct fw_rsc_hdr { + u32 type; + u8 data[]; +} __packed; + +/** + * enum fw_resource_type - types of resource entries + * + * @RSC_CARVEOUT: request for allocation of a physically contiguous + * memory region. + * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. + * @RSC_TRACE: announces the availability of a trace buffer into which + * the remote processor will be writing logs. + * @RSC_VDEV: declare support for a virtio device, and serve as its + * virtio header. + * @RSC_LAST: just keep this one at the end of standard resources + * @RSC_VENDOR_START: start of the vendor specific resource types range + * @RSC_VENDOR_END: end of the vendor specific resource types range + * + * For more details regarding a specific resource type, please see its + * dedicated structure below. + * + * Please note that these values are used as indices to the rproc_handle_rsc + * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to + * check the validity of an index before the lookup table is accessed, so + * please update it as needed. + */ +enum fw_resource_type { + RSC_CARVEOUT = 0, + RSC_DEVMEM = 1, + RSC_TRACE = 2, + RSC_VDEV = 3, + RSC_LAST = 4, + RSC_VENDOR_START = 128, + RSC_VENDOR_END = 512, +}; + +#define FW_RSC_ADDR_ANY (-1) + +/** + * struct fw_rsc_carveout - physically contiguous memory request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested memory region + * + * This resource entry requests the host to allocate a physically contiguous + * memory region. + * + * These request entries should precede other firmware resource entries, + * as other entries might request placing other data objects inside + * these memory regions (e.g. data/code segments, trace resource entries, ...). + * + * Allocating memory this way helps utilizing the reserved physical memory + * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries + * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB + * pressure is important; it may have a substantial impact on performance. + * + * If the firmware is compiled with static addresses, then @da should specify + * the expected device address of this memory region. If @da is set to + * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then + * overwrite @da with the dynamically allocated address. + * + * We will always use @da to negotiate the device addresses, even if it + * isn't using an iommu. In that case, though, it will obviously contain + * physical addresses. + * + * Some remote processors needs to know the allocated physical address + * even if they do use an iommu. This is needed, e.g., if they control + * hardware accelerators which access the physical memory directly (this + * is the case with OMAP4 for instance). In that case, the host will + * overwrite @pa with the dynamically allocated physical address. + * Generally we don't want to expose physical addresses if we don't have to + * (remote processors are generally _not_ trusted), so we might want to + * change this to happen _only_ when explicitly required by the hardware. + * + * @flags is used to provide IOMMU protection flags, and @name should + * (optionally) contain a human readable name of this carveout region + * (mainly for debugging purposes). + */ +struct fw_rsc_carveout { + u32 da; + u32 pa; + u32 len; + u32 flags; + u32 reserved; + u8 name[32]; +} __packed; + +/** + * struct fw_rsc_devmem - iommu mapping request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested region to be mapped + * + * This resource entry requests the host to iommu map a physically contiguous + * memory region. This is needed in case the remote processor requires + * access to certain memory-based peripherals; _never_ use it to access + * regular memory. + * + * This is obviously only needed if the remote processor is accessing memory + * via an iommu. + * + * @da should specify the required device address, @pa should specify + * the physical address we want to map, @len should specify the size of + * the mapping and @flags is the IOMMU protection flags. As always, @name may + * (optionally) contain a human readable name of this mapping (mainly for + * debugging purposes). + * + * Note: at this point we just "trust" those devmem entries to contain valid + * physical addresses, but this isn't safe and will be changed: eventually we + * want remoteproc implementations to provide us ranges of physical addresses + * the firmware is allowed to request, and not allow firmwares to request + * access to physical addresses that are outside those ranges. + */ +struct fw_rsc_devmem { + u32 da; + u32 pa; + u32 len; + u32 flags; + u32 reserved; + u8 name[32]; +} __packed; + +/** + * struct fw_rsc_trace - trace buffer declaration + * @da: device address + * @len: length (in bytes) + * @reserved: reserved (must be zero) + * @name: human-readable name of the trace buffer + * + * This resource entry provides the host information about a trace buffer + * into which the remote processor will write log messages. + * + * @da specifies the device address of the buffer, @len specifies + * its size, and @name may contain a human readable name of the trace buffer. + * + * After booting the remote processor, the trace buffers are exposed to the + * user via debugfs entries (called trace0, trace1, etc..). + */ +struct fw_rsc_trace { + u32 da; + u32 len; + u32 reserved; + u8 name[32]; +} __packed; + +/** + * struct fw_rsc_vdev_vring - vring descriptor entry + * @da: device address + * @align: the alignment between the consumer and producer parts of the vring + * @num: num of buffers supported by this vring (must be power of two) + * @notifyid: a unique rproc-wide notify index for this vring. This notify + * index is used when kicking a remote processor, to let it know that this + * vring is triggered. + * @pa: physical address + * + * This descriptor is not a resource entry by itself; it is part of the + * vdev resource type (see below). + * + * Note that @da should either contain the device address where + * the remote processor is expecting the vring, or indicate that + * dynamically allocation of the vring's device address is supported. + */ +struct fw_rsc_vdev_vring { + u32 da; + u32 align; + u32 num; + u32 notifyid; + u32 pa; +} __packed; + +/** + * struct fw_rsc_vdev - virtio device header + * @id: virtio device id (as in virtio_ids.h) + * @notifyid: a unique rproc-wide notify index for this vdev. This notify + * index is used when kicking a remote processor, to let it know that the + * status/features of this vdev have changes. + * @dfeatures: specifies the virtio device features supported by the firmware + * @gfeatures: a place holder used by the host to write back the + * negotiated features that are supported by both sides. + * @config_len: the size of the virtio config space of this vdev. The config + * space lies in the resource table immediate after this vdev header. + * @status: a place holder where the host will indicate its virtio progress. + * @num_of_vrings: indicates how many vrings are described in this vdev header + * @reserved: reserved (must be zero) + * @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. + * + * This resource is a virtio device header: it provides information about + * the vdev, and is then used by the host and its peer remote processors + * to negotiate and share certain virtio properties. + * + * By providing this resource entry, the firmware essentially asks remoteproc + * to statically allocate a vdev upon registration of the rproc (dynamic vdev + * allocation is not yet supported). + * + * Note: + * 1. unlike virtualization systems, the term 'host' here means + * the Linux side which is running remoteproc to control the remote + * processors. We use the name 'gfeatures' to comply with virtio's terms, + * though there isn't really any virtualized guest OS here: it's the host + * which is responsible for negotiating the final features. + * Yeah, it's a bit confusing. + * + * 2. immediately following this structure is the virtio config space for + * this vdev (which is specific to the vdev; for more info, read the virtio + * spec). The size of the config space is specified by @config_len. + */ +struct fw_rsc_vdev { + u32 id; + u32 notifyid; + u32 dfeatures; + u32 gfeatures; + u32 config_len; + u8 status; + u8 num_of_vrings; + u8 reserved[2]; + struct fw_rsc_vdev_vring vring[]; +} __packed; + +/** + * rsc_table_for_each_entry() - iterate over all entries in a resource table + * @table: pointer to the resource table + * @table_sz: total size of the table buffer in bytes + * @dev: device used for error logging + * @cb: callback invoked for each entry: + * @type - value from enum fw_resource_type + * @rsc - pointer to the entry payload (past struct fw_rsc_hdr) + * @offset - byte offset of the payload within the table; callers + * that write back into the table (e.g. to record a + * dynamically allocated address) use this to locate the + * entry for later update + * @avail - bytes available in the payload + * @data - caller-supplied private pointer + * Return 0 to continue iteration, non-zero to stop. + * @data: private pointer forwarded to @cb on every call + * + * Iterates over every resource entry in @table, performing the standard + * truncation check, and invokes @cb for each one. Iteration stops on the + * first non-zero return from @cb or on a malformed table. + * + * Returns 0 after a complete iteration, -EINVAL if the table is truncated, + * or the first non-zero value returned by @cb. + */ +static inline int rsc_table_for_each_entry(struct resource_table *table, + size_t table_sz, + struct device *dev, + int (*cb)(u32 type, void *rsc, + int offset, int avail, + void *data), + void *data) { + int i, ret; + + for (i = 0; i < table->num; i++) { + int offset = table->offset[i]; + struct fw_rsc_hdr *hdr = (void *)table + offset; + int avail = table_sz - offset - sizeof(*hdr); + int rsc_offset = offset + sizeof(*hdr); + void *rsc = (void *)hdr + sizeof(*hdr); + + if (avail < 0) { + dev_err(dev, "rsc table is truncated\n"); + return -EINVAL; + } + + ret = cb(hdr->type, rsc, rsc_offset, avail, data); + if (ret) + return ret; + } + + return 0; +} + +#endif /* RSC_TABLE_H */ |
