Pull remoteproc updates from Bjorn Andersson: - Add i.MX94 support to the i.MX remoteproc driver, covering the Cortex-M7 and Cortex-M33 Sync cores. This also fixes programming of non-zero System Manager CPU/LMM reset vectors. - Move the remoteproc resource table definitions to a separate header, so they can be used by clients that do not otherwise depend on remoteproc. Switch the firmware resource handling over to the common iterator. - Update the Xilinx R5F remoteproc driver to check the remote core state before attaching, drop a binding header dependency, and add firmware-name based auto boot support. - Add Qualcomm Hawi ADSP/CDSP bindings, together with Shikra RPM bindings and CDSP, LPAICP, and MPSS PAS support. Fix a Qualcomm minidump leak, clean up PAS and WCSS reset handling, and make the user-visible Qualcomm naming consistent. - Remove a duplicate STM32_RPROC Kconfig dependency and make i.MX remoteproc instances use the device node name so multiple processors can be distinguished in sysfs. * tag 'rproc-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: remoteproc: qcom: pas: Drop start/stop completion from struct qcom_pas remoteproc: qcom: pas: Add Shikra remoteproc support dt-bindings: remoteproc: qcom,shikra-pas: Document Shikra PAS remoteprocs dt-bindings: remoteproc: Add Shikra RPM processor compatible remoteproc: qcom: Unify user-visible "Qualcomm" name remoteproc: qcom: Fix leak when custom dump_segments addition fails remoteproc: qcom_q6v5_wcss: drop redundant wcss_q6_bcr_reset dt-bindings: remoteproc: qcom,sm8550-pas: Add Hawi CDSP compatible dt-bindings: remoteproc: qcom,sm8550-pas: Add Hawi ADSP compatible remoteproc: xlnx: Enable auto boot feature dt-bindings: remoteproc: xlnx: Add firmware-name property remoteproc: xlnx: Remove binding header dependency remoteproc: imx_rproc: Use device node name as processor name remoteproc: use rsc_table_for_each_entry() in rproc_handle_resources() remoteproc: Move resource table data structure to its own header remoteproc: xlnx: Check remote core state remoteproc: imx_rproc: Add support for i.MX94 remoteproc: imx_rproc: Program non-zero SM CPU/LMM reset vector dt-bindings: remoteproc: imx-rproc: Support i.MX94 remoteproc: Dead code cleanup in Kconfig for STM32_RPROC
Unified · Split
| @@ -28,6 +28,9 @@ properties: · 27 unmodified lines | |||
| 28 | - fsl,imx8qxp-cm4 | 28 | - fsl,imx8qxp-cm4 |
| 29 | - fsl,imx8ulp-cm33 | 29 | - fsl,imx8ulp-cm33 |
| 30 | - fsl,imx93-cm33 | 30 | - fsl,imx93-cm33 |
| 31 | - fsl,imx94-cm33s | ||
| 32 | - fsl,imx94-cm70 | ||
| 33 | - fsl,imx94-cm71 | ||
| 31 | - fsl,imx95-cm7 | 34 | - fsl,imx95-cm7 |
| 32 | 35 | ||
| 33 | clocks: | 36 | clocks: |
| @@ -87,6 +87,7 @@ properties: · 86 unmodified lines | |||
| 87 | - qcom,qcm2290-rpm-proc | 87 | - qcom,qcm2290-rpm-proc |
| 88 | - qcom,qcs404-rpm-proc | 88 | - qcom,qcs404-rpm-proc |
| 89 | - qcom,sdm660-rpm-proc | 89 | - qcom,sdm660-rpm-proc |
| 90 | - qcom,shikra-rpm-proc | ||
| 90 | - qcom,sm6115-rpm-proc | 91 | - qcom,sm6115-rpm-proc |
| 91 | - qcom,sm6125-rpm-proc | 92 | - qcom,sm6125-rpm-proc |
| 92 | - qcom,sm6375-rpm-proc | 93 | - qcom,sm6375-rpm-proc |
| @@ -0,0 +1,167 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/remoteproc/qcom,shikra-pas.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm Shikra SoC Peripheral Authentication Service | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bibek Kumar Patro <bibek.patro@oss.qualcomm.com> | ||
| 11 | - Komal Bajaj <komal.bajaj@oss.qualcomm.com> | ||
| 12 | |||
| 13 | description: | ||
| 14 | Qualcomm Shikra SoC Peripheral Authentication Service loads and boots | ||
| 15 | firmware on the Qualcomm DSP Hexagon cores. | ||
| 16 | |||
| 17 | properties: | ||
| 18 | compatible: | ||
| 19 | enum: | ||
| 20 | - qcom,shikra-cdsp-pas | ||
| 21 | - qcom,shikra-lpaicp-pas | ||
| 22 | - qcom,shikra-mpss-pas | ||
| 23 | |||
| 24 | reg: | ||
| 25 | maxItems: 1 | ||
| 26 | |||
| 27 | clocks: | ||
| 28 | items: | ||
| 29 | - description: XO clock | ||
| 30 | |||
| 31 | clock-names: | ||
| 32 | items: | ||
| 33 | - const: xo | ||
| 34 | |||
| 35 | memory-region: | ||
| 36 | minItems: 1 | ||
| 37 | maxItems: 2 | ||
| 38 | |||
| 39 | smd-edge: false | ||
| 40 | |||
| 41 | firmware-name: | ||
| 42 | minItems: 1 | ||
| 43 | items: | ||
| 44 | - description: Firmware name of the Hexagon core | ||
| 45 | - description: Firmware name of the Hexagon Devicetree | ||
| 46 | |||
| 47 | glink-edge: | ||
| 48 | $ref: /schemas/remoteproc/qcom,glink-edge.yaml# | ||
| 49 | description: | ||
| 50 | Qualcomm G-Link subnode which represents communication edge, channels | ||
| 51 | and devices related to the remoteproc core. | ||
| 52 | unevaluatedProperties: false | ||
| 53 | |||
| 54 | qcom,smem-states: | ||
| 55 | $ref: /schemas/types.yaml#/definitions/phandle-array | ||
| 56 | description: States used by the AP to signal the Hexagon core | ||
| 57 | items: | ||
| 58 | - description: Stop the remote processor | ||
| 59 | items: | ||
| 60 | - description: Phandle to the Shared Memory Point 2 Point device | ||
| 61 | handling the communication with a remote processor | ||
| 62 | - description: Single bit index to toggle in the value sent to | ||
| 63 | the remote processor | ||
| 64 | maximum: 32 | ||
| 65 | |||
| 66 | qcom,smem-state-names: | ||
| 67 | description: The names of the state bits used for SMP2P output | ||
| 68 | items: | ||
| 69 | - const: stop | ||
| 70 | |||
| 71 | required: | ||
| 72 | - compatible | ||
| 73 | - reg | ||
| 74 | - memory-region | ||
| 75 | |||
| 76 | allOf: | ||
| 77 | - $ref: /schemas/remoteproc/qcom,pas-common.yaml# | ||
| 78 | |||
| 79 | - if: | ||
| 80 | properties: | ||
| 81 | compatible: | ||
| 82 | enum: | ||
| 83 | - qcom,shikra-cdsp-pas | ||
| 84 | - qcom,shikra-mpss-pas | ||
| 85 | then: | ||
| 86 | properties: | ||
| 87 | interrupts: | ||
| 88 | minItems: 6 | ||
| 89 | interrupt-names: | ||
| 90 | minItems: 6 | ||
| 91 | memory-region: | ||
| 92 | maxItems: 1 | ||
| 93 | firmware-name: | ||
| 94 | maxItems: 1 | ||
| 95 | power-domains: | ||
| 96 | items: | ||
| 97 | - description: CX power domain | ||
| 98 | power-domain-names: | ||
| 99 | items: | ||
| 100 | - const: cx | ||
| 101 | |||
| 102 | - if: | ||
| 103 | properties: | ||
| 104 | compatible: | ||
| 105 | enum: | ||
| 106 | - qcom,shikra-lpaicp-pas | ||
| 107 | then: | ||
| 108 | properties: | ||
| 109 | interrupts: | ||
| 110 | maxItems: 5 | ||
| 111 | interrupt-names: | ||
| 112 | maxItems: 5 | ||
| 113 | memory-region: | ||
| 114 | minItems: 2 | ||
| 115 | firmware-name: | ||
| 116 | minItems: 2 | ||
| 117 | power-domains: false | ||
| 118 | power-domain-names: false | ||
| 119 | |||
| 120 | unevaluatedProperties: false | ||
| 121 | |||
| 122 | examples: | ||
| 123 | - | | ||
| 124 | #include <dt-bindings/clock/qcom,rpmcc.h> | ||
| 125 | #include <dt-bindings/interconnect/qcom,icc.h> | ||
| 126 | #include <dt-bindings/interconnect/qcom,rpm-icc.h> | ||
| 127 | #include <dt-bindings/interconnect/qcom,shikra.h> | ||
| 128 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 129 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 130 | #include <dt-bindings/power/qcom-rpmpd.h> | ||
| 131 | |||
| 132 | remoteproc@b300000 { | ||
| 133 | compatible = "qcom,shikra-cdsp-pas"; | ||
| 134 | reg = <0x0b300000 0x100000>; | ||
| 135 | |||
| 136 | interrupts-extended = <&intc GIC_SPI 265 IRQ_TYPE_EDGE_RISING>, | ||
| 137 | <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, | ||
| 138 | <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, | ||
| 139 | <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, | ||
| 140 | <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, | ||
| 141 | <&cdsp_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; | ||
| 142 | interrupt-names = "wdog", "fatal", "ready", | ||
| 143 | "handover", "stop-ack", "shutdown-ack"; | ||
| 144 | |||
| 145 | clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; | ||
| 146 | clock-names = "xo"; | ||
| 147 | |||
| 148 | interconnects = <&mem_noc MASTER_AMPSS_M0 RPM_ALWAYS_TAG | ||
| 149 | &mc_virt SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; | ||
| 150 | |||
| 151 | power-domains = <&rpmpd RPMHPD_CX>; | ||
| 152 | power-domain-names = "cx"; | ||
| 153 | |||
| 154 | memory-region = <&cdsp_mem>; | ||
| 155 | |||
| 156 | qcom,smem-states = <&cdsp_smp2p_out 0>; | ||
| 157 | qcom,smem-state-names = "stop"; | ||
| 158 | |||
| 159 | firmware-name = "qcom/shikra/cdsp.mbn"; | ||
| 160 | |||
| 161 | glink-edge { | ||
| 162 | interrupts = <GIC_SPI 261 IRQ_TYPE_EDGE_RISING>; | ||
| 163 | mboxes = <&apcs_glb 4>; | ||
| 164 | qcom,remote-pid = <5>; | ||
| 165 | label = "cdsp"; | ||
| 166 | }; | ||
| 167 | }; | ||
| @@ -30,12 +30,14 @@ properties: · 29 unmodified lines | |||
| 30 | - items: | 30 | - items: |
| 31 | - enum: | 31 | - enum: |
| 32 | - qcom,glymur-adsp-pas | 32 | - qcom,glymur-adsp-pas |
| 33 | - qcom,hawi-adsp-pas | ||
| 33 | - qcom,kaanapali-adsp-pas | 34 | - qcom,kaanapali-adsp-pas |
| 34 | - qcom,sm8750-adsp-pas | 35 | - qcom,sm8750-adsp-pas |
| 35 | - const: qcom,sm8550-adsp-pas | 36 | - const: qcom,sm8550-adsp-pas |
| 36 | - items: | 37 | - items: |
| 37 | - enum: | 38 | - enum: |
| 38 | - qcom,glymur-cdsp-pas | 39 | - qcom,glymur-cdsp-pas |
| 40 | - qcom,hawi-cdsp-pas | ||
| 39 | - qcom,kaanapali-cdsp-pas | 41 | - qcom,kaanapali-cdsp-pas |
| 40 | - const: qcom,sm8550-cdsp-pas | 42 | - const: qcom,sm8550-cdsp-pas |
| 41 | - items: | 43 | - items: |
| @@ -104,6 +106,8 @@ allOf: · 62 unmodified lines | |||
| 104 | enum: | 106 | enum: |
| 105 | - qcom,glymur-adsp-pas | 107 | - qcom,glymur-adsp-pas |
| 106 | - qcom,glymur-cdsp-pas | 108 | - qcom,glymur-cdsp-pas |
| 109 | - qcom,hawi-adsp-pas | ||
| 110 | - qcom,hawi-cdsp-pas | ||
| 107 | - qcom,kaanapali-adsp-pas | 111 | - qcom,kaanapali-adsp-pas |
| 108 | - qcom,kaanapali-cdsp-pas | 112 | - qcom,kaanapali-cdsp-pas |
| 109 | - qcom,sm8750-adsp-pas | 113 | - qcom,sm8750-adsp-pas |
| @@ -128,6 +128,10 @@ patternProperties: · 127 unmodified lines | |||
| 128 | - description: vring1 | 128 | - description: vring1 |
| 129 | additionalItems: true | 129 | additionalItems: true |
| 130 | 130 | ||
| 131 | firmware-name: | ||
| 132 | maxItems: 1 | ||
| 133 | description: default firmware to load | ||
| 134 | |||
| 131 | required: | 135 | required: |
| 132 | - compatible | 136 | - compatible |
| 133 | - reg | 137 | - reg |
| @@ -1450,6 +1450,34 @@ int zynqmp_pm_get_node_status(const u32 node, u32 *const status, · 1449 unmodified lines | |||
| 1450 | } | 1450 | } |
| 1451 | EXPORT_SYMBOL_GPL(zynqmp_pm_get_node_status); | 1451 | EXPORT_SYMBOL_GPL(zynqmp_pm_get_node_status); |
| 1452 | 1452 | ||
| 1453 | /** | ||
| 1454 | * zynqmp_pm_get_rpu_node_status - PM call to request a RPU node's current power state | ||
| 1455 | * @node: ID of the RPU component or sub-system in question | ||
| 1456 | * @status: Current operating state of the requested RPU node. | ||
| 1457 | * @requirements: Current requirements asserted on the RPU node. | ||
| 1458 | * @usage: Usage information, used for RPU slave nodes only: | ||
| 1459 | * PM_USAGE_NO_MASTER - No master is currently using | ||
| 1460 | * the node | ||
| 1461 | * PM_USAGE_CURRENT_MASTER - Only requesting master is | ||
| 1462 | * currently using the node | ||
| 1463 | * PM_USAGE_OTHER_MASTER - Only other masters are | ||
| 1464 | * currently using the node | ||
| 1465 | * PM_USAGE_BOTH_MASTERS - Both the current and at least | ||
| 1466 | * one other master is currently | ||
| 1467 | * using the node | ||
| 1468 | * | ||
| 1469 | * Return: Returns status, either success or error+reason | ||
| 1470 | */ | ||
| 1471 | int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status, | ||
| 1472 | u32 *const requirements, u32 *const usage) | ||
| 1473 | { | ||
| 1474 | if (zynqmp_pm_feature(PM_GET_NODE_STATUS) < PM_API_VERSION_2) | ||
| 1475 | return -EOPNOTSUPP; | ||
| 1476 | |||
| 1477 | return zynqmp_pm_get_node_status(node, status, requirements, usage); | ||
| 1478 | } | ||
| 1479 | EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_node_status); | ||
| 1480 | |||
| 1453 | /** | 1481 | /** |
| 1454 | * zynqmp_pm_force_pwrdwn - PM call to request for another PU or subsystem to | 1482 | * zynqmp_pm_force_pwrdwn - PM call to request for another PU or subsystem to |
| 1455 | * be powered down forcefully | 1483 | * be powered down forcefully |
| @@ -176,7 +176,7 @@ config QCOM_Q6V5_COMMON · 175 unmodified lines | |||
| 176 | depends on QCOM_SMEM | 176 | depends on QCOM_SMEM |
| 177 | 177 | ||
| 178 | config QCOM_Q6V5_ADSP | 178 | config QCOM_Q6V5_ADSP |
| 179 | tristate "Qualcomm Technology Inc ADSP Peripheral Image Loader" | 179 | tristate "Qualcomm ADSP Peripheral Image Loader" |
| 180 | depends on OF && ARCH_QCOM | 180 | depends on OF && ARCH_QCOM |
| 181 | depends on QCOM_SMEM | 181 | depends on QCOM_SMEM |
| 182 | depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n | 182 | depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n |
| @@ -316,7 +316,6 @@ config ST_SLIM_REMOTEPROC · 133 unmodified lines | |||
| 316 | config STM32_RPROC | 316 | config STM32_RPROC |
| 317 | tristate "STM32 remoteproc support" | 317 | tristate "STM32 remoteproc support" |
| 318 | depends on ARCH_STM32 || COMPILE_TEST | 318 | depends on ARCH_STM32 || COMPILE_TEST |
| 319 | depends on REMOTEPROC | ||
| 320 | select MAILBOX | 319 | select MAILBOX |
| 321 | help | 320 | help |
| 322 | Say y here to support STM32 MCU processors via the | 321 | Say y here to support STM32 MCU processors via the |
| @@ -145,6 +145,41 @@ static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = { · 144 unmodified lines | |||
| 145 | { 0x80000000, 0x80000000, 0x50000000, 0 }, | 145 | { 0x80000000, 0x80000000, 0x50000000, 0 }, |
| 146 | }; | 146 | }; |
| 147 | 147 | ||
| 148 | static const struct imx_rproc_att imx_rproc_att_imx94_m70[] = { | ||
| 149 | /* dev addr , sys addr , size , flags */ | ||
| 150 | /* TCM CODE NON-SECURE */ | ||
| 151 | { 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, | ||
| 152 | /* TCM SYS NON-SECURE*/ | ||
| 153 | { 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM }, | ||
| 154 | |||
| 155 | /* DDR */ | ||
| 156 | { 0x80000000, 0x80000000, 0x10000000, 0 }, | ||
| 157 | }; | ||
| 158 | |||
| 159 | static const struct imx_rproc_att imx_rproc_att_imx94_m71[] = { | ||
| 160 | /* dev addr , sys addr , size , flags */ | ||
| 161 | /* TCM CODE NON-SECURE */ | ||
| 162 | { 0x00000000, 0x202C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, | ||
| 163 | /* TCM SYS NON-SECURE*/ | ||
| 164 | { 0x20000000, 0x20300000, 0x00040000, ATT_OWN | ATT_IOMEM }, | ||
| 165 | |||
| 166 | /* DDR */ | ||
| 167 | { 0x80000000, 0x80000000, 0x10000000, 0 }, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static const struct imx_rproc_att imx_rproc_att_imx94_m33s[] = { | ||
| 171 | /* dev addr , sys addr , size , flags */ | ||
| 172 | /* TCM CODE NON-SECURE */ | ||
| 173 | { 0x0FFC0000, 0x209C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, | ||
| 174 | /* TCM SYS NON-SECURE */ | ||
| 175 | { 0x20000000, 0x20A00000, 0x00040000, ATT_OWN | ATT_IOMEM }, | ||
| 176 | /* M33S OCRAM NON-SECURE */ | ||
| 177 | { 0x20800000, 0x20800000, 0x180000, ATT_OWN | ATT_IOMEM }, | ||
| 178 | |||
| 179 | /* DDR */ | ||
| 180 | { 0x80000000, 0x80000000, 0x10000000, 0 }, | ||
| 181 | }; | ||
| 182 | |||
| 148 | static const struct imx_rproc_att imx_rproc_att_imx93[] = { | 183 | static const struct imx_rproc_att imx_rproc_att_imx93[] = { |
| 149 | /* dev addr , sys addr , size , flags */ | 184 | /* dev addr , sys addr , size , flags */ |
| 150 | /* TCM CODE NON-SECURE */ | 185 | /* TCM CODE NON-SECURE */ |
| @@ -339,13 +374,32 @@ static int imx_rproc_scu_api_start(struct rproc *rproc) · 188 unmodified lines | |||
| 339 | return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); | 374 | return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); |
| 340 | } | 375 | } |
| 341 | 376 | ||
| 377 | static u64 imx_rproc_sm_get_reset_vector(struct rproc *rproc) | ||
| 378 | { | ||
| 379 | struct imx_rproc *priv = rproc->priv; | ||
| 380 | u32 reset_vector_mask = priv->dcfg->reset_vector_mask ?: GENMASK(31, 0); | ||
| 381 | |||
| 382 | /* | ||
| 383 | * The hardware fetches the first two words from reset_vectors | ||
| 384 | * (hardware reset address) and populates SP and PC using the first | ||
| 385 | * two words. Execution proceeds from PC. The ELF entry point does | ||
| 386 | * not always match the hardware reset address. | ||
| 387 | * To derive the correct hardware reset address, the lower address | ||
| 388 | * bits must be masked off before programming the reset vector. | ||
| 389 | */ | ||
| 390 | return rproc->bootaddr & reset_vector_mask; | ||
| 391 | } | ||
| 392 | |||
| 342 | static int imx_rproc_sm_cpu_start(struct rproc *rproc) | 393 | static int imx_rproc_sm_cpu_start(struct rproc *rproc) |
| 343 | { | 394 | { |
| 344 | struct imx_rproc *priv = rproc->priv; | 395 | struct imx_rproc *priv = rproc->priv; |
| 345 | const struct imx_rproc_dcfg *dcfg = priv->dcfg; | 396 | const struct imx_rproc_dcfg *dcfg = priv->dcfg; |
| 397 | u64 reset_vector; | ||
| 346 | int ret; | 398 | int ret; |
| 347 | 399 | ||
| 348 | ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false); | 400 | reset_vector = imx_rproc_sm_get_reset_vector(rproc); |
| 401 | |||
| 402 | ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, reset_vector, true, false, false); | ||
| 349 | if (ret) { | 403 | if (ret) { |
| 350 | dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret); | 404 | dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret); |
| 351 | return ret; | 405 | return ret; |
| @@ -359,13 +413,16 @@ static int imx_rproc_sm_lmm_start(struct rproc *rproc) · 7 unmodified lines | |||
| 359 | struct imx_rproc *priv = rproc->priv; | 413 | struct imx_rproc *priv = rproc->priv; |
| 360 | const struct imx_rproc_dcfg *dcfg = priv->dcfg; | 414 | const struct imx_rproc_dcfg *dcfg = priv->dcfg; |
| 361 | struct device *dev = priv->dev; | 415 | struct device *dev = priv->dev; |
| 416 | u64 reset_vector; | ||
| 362 | int ret; | 417 | int ret; |
| 363 | 418 | ||
| 419 | reset_vector = imx_rproc_sm_get_reset_vector(rproc); | ||
| 420 | |||
| 364 | /* | 421 | /* |
| 365 | * If the remoteproc core can't start the M7, it will already be | 422 | * If the remoteproc core can't start the M7, it will already be |
| 366 | * handled in imx_rproc_sm_lmm_prepare(). | 423 | * handled in imx_rproc_sm_lmm_prepare(). |
| 367 | */ | 424 | */ |
| 368 | ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0); | 425 | ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, reset_vector); |
| 369 | if (ret) { | 426 | if (ret) { |
| 370 | dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n", | 427 | dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n", |
| 371 | dcfg->lmid, dcfg->cpuid, ret); | 428 | dcfg->lmid, dcfg->cpuid, ret); |
| @@ -1230,8 +1287,7 @@ static int imx_rproc_probe(struct platform_device *pdev) · 858 unmodified lines | |||
| 1230 | const struct imx_rproc_dcfg *dcfg; | 1287 | const struct imx_rproc_dcfg *dcfg; |
| 1231 | int ret; | 1288 | int ret; |
| 1232 | 1289 | ||
| 1233 | /* set some other name then imx */ | 1290 | rproc = devm_rproc_alloc(dev, np->name, &imx_rproc_ops, |
| 1234 | rproc = devm_rproc_alloc(dev, "imx-rproc", &imx_rproc_ops, | ||
| 1235 | NULL, sizeof(*priv)); | 1291 | NULL, sizeof(*priv)); |
| 1236 | if (!rproc) | 1292 | if (!rproc) |
| 1237 | return -ENOMEM; | 1293 | return -ENOMEM; |
| @@ -1455,6 +1511,33 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { · 217 unmodified lines | |||
| 1455 | .flags = IMX_RPROC_NEED_CLKS, | 1511 | .flags = IMX_RPROC_NEED_CLKS, |
| 1456 | }; | 1512 | }; |
| 1457 | 1513 | ||
| 1514 | static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m70 = { | ||
| 1515 | .att = imx_rproc_att_imx94_m70, | ||
| 1516 | .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m70), | ||
| 1517 | .ops = &imx_rproc_ops_sm_lmm, | ||
| 1518 | .cpuid = 1, | ||
| 1519 | .lmid = 2, | ||
| 1520 | .reset_vector_mask = GENMASK_U32(31, 16), | ||
| 1521 | }; | ||
| 1522 | |||
| 1523 | static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m71 = { | ||
| 1524 | .att = imx_rproc_att_imx94_m71, | ||
| 1525 | .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m71), | ||
| 1526 | .ops = &imx_rproc_ops_sm_lmm, | ||
| 1527 | .cpuid = 7, | ||
| 1528 | .lmid = 3, | ||
| 1529 | .reset_vector_mask = GENMASK_U32(31, 16), | ||
| 1530 | }; | ||
| 1531 | |||
| 1532 | static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m33s = { | ||
| 1533 | .att = imx_rproc_att_imx94_m33s, | ||
| 1534 | .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m33s), | ||
| 1535 | .ops = &imx_rproc_ops_sm_lmm, | ||
| 1536 | .cpuid = 8, | ||
| 1537 | .lmid = 1, | ||
| 1538 | .reset_vector_mask = GENMASK_U32(31, 16), | ||
| 1539 | }; | ||
| 1540 | |||
| 1458 | static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { | 1541 | static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { |
| 1459 | .att = imx_rproc_att_imx95_m7, | 1542 | .att = imx_rproc_att_imx95_m7, |
| 1460 | .att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7), | 1543 | .att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7), |
| @@ -1462,6 +1545,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { · 1 unmodified line | |||
| 1462 | /* Must align with System Manager Firmware */ | 1545 | /* Must align with System Manager Firmware */ |
| 1463 | .cpuid = 1, /* Use 1 as cpu id for M7 core */ | 1546 | .cpuid = 1, /* Use 1 as cpu id for M7 core */ |
| 1464 | .lmid = 1, /* Use 1 as Logical Machine ID where M7 resides */ | 1547 | .lmid = 1, /* Use 1 as Logical Machine ID where M7 resides */ |
| 1548 | .reset_vector_mask = GENMASK_U32(31, 16), | ||
| 1465 | }; | 1549 | }; |
| 1466 | 1550 | ||
| 1467 | static const struct of_device_id imx_rproc_of_match[] = { | 1551 | static const struct of_device_id imx_rproc_of_match[] = { |
| @@ -1478,6 +1562,9 @@ static const struct of_device_id imx_rproc_of_match[] = { · 10 unmodified lines | |||
| 1478 | { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm }, | 1562 | { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm }, |
| 1479 | { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, | 1563 | { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, |
| 1480 | { .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 }, | 1564 | { .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 }, |
| 1565 | { .compatible = "fsl,imx94-cm70", .data = &imx_rproc_cfg_imx94_m70 }, | ||
| 1566 | { .compatible = "fsl,imx94-cm71", .data = &imx_rproc_cfg_imx94_m71 }, | ||
| 1567 | { .compatible = "fsl,imx94-cm33s", .data = &imx_rproc_cfg_imx94_m33s }, | ||
| 1481 | { .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 }, | 1568 | { .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 }, |
| 1482 | {}, | 1569 | {}, |
| 1483 | }; | 1570 | }; |
| @@ -41,6 +41,8 @@ struct imx_rproc_dcfg { · 40 unmodified lines | |||
| 41 | /* For System Manager(SM) based SoCs */ | 41 | /* For System Manager(SM) based SoCs */ |
| 42 | u32 cpuid; /* ID of the remote core */ | 42 | u32 cpuid; /* ID of the remote core */ |
| 43 | u32 lmid; /* ID of the Logcial Machine */ | 43 | u32 lmid; /* ID of the Logcial Machine */ |
| 44 | /* reset_vector = elf_entry_addr & reset_vector_mask */ | ||
| 45 | u32 reset_vector_mask; | ||
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 46 | #endif /* _IMX_RPROC_H */ | 48 | #endif /* _IMX_RPROC_H */ |
| @@ -109,6 +109,7 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy · 108 unmodified lines | |||
| 109 | struct minidump_region __iomem *ptr; | 109 | struct minidump_region __iomem *ptr; |
| 110 | struct minidump_region region; | 110 | struct minidump_region region; |
| 111 | int seg_cnt, i; | 111 | int seg_cnt, i; |
| 112 | int ret = 0; | ||
| 112 | dma_addr_t da; | 113 | dma_addr_t da; |
| 113 | size_t size; | 114 | size_t size; |
| 114 | char *name; | 115 | char *name; |
| @@ -129,17 +130,22 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy · 14 unmodified lines | |||
| 129 | if (le32_to_cpu(region.valid) == MINIDUMP_REGION_VALID) { | 130 | if (le32_to_cpu(region.valid) == MINIDUMP_REGION_VALID) { |
| 130 | name = kstrndup(region.name, MAX_REGION_NAME_LENGTH - 1, GFP_KERNEL); | 131 | name = kstrndup(region.name, MAX_REGION_NAME_LENGTH - 1, GFP_KERNEL); |
| 131 | if (!name) { | 132 | if (!name) { |
| 132 | iounmap(ptr); | 133 | ret = -ENOMEM; |
| 133 | return -ENOMEM; | 134 | break; |
| 134 | } | 135 | } |
| 135 | da = le64_to_cpu(region.address); | 136 | da = le64_to_cpu(region.address); |
| 136 | size = le64_to_cpu(region.size); | 137 | size = le64_to_cpu(region.size); |
| 137 | rproc_coredump_add_custom_segment(rproc, da, size, rproc_dumpfn_t, name); | 138 | ret = rproc_coredump_add_custom_segment(rproc, da, size, rproc_dumpfn_t, |
| 139 | name); | ||
| 140 | if (ret) { | ||
| 141 | kfree(name); | ||
| 142 | break; | ||
| 143 | } | ||
| 138 | } | 144 | } |
| 139 | } | 145 | } |
| 140 | 146 | ||
| 141 | iounmap(ptr); | 147 | iounmap(ptr); |
| 142 | return 0; | 148 | return ret; |
| 143 | } | 149 | } |
| 144 | 150 | ||
| 145 | void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, | 151 | void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, |
| @@ -92,9 +92,6 @@ struct qcom_pas { · 91 unmodified lines | |||
| 92 | const struct firmware *firmware; | 92 | const struct firmware *firmware; |
| 93 | const struct firmware *dtb_firmware; | 93 | const struct firmware *dtb_firmware; |
| 94 | 94 | ||
| 95 | struct completion start_done; | ||
| 96 | struct completion stop_done; | ||
| 97 | |||
| 98 | phys_addr_t mem_phys; | 95 | phys_addr_t mem_phys; |
| 99 | phys_addr_t dtb_mem_phys; | 96 | phys_addr_t dtb_mem_phys; |
| 100 | phys_addr_t mem_reloc; | 97 | phys_addr_t mem_reloc; |
| @@ -1457,6 +1454,51 @@ static const struct qcom_pas_data sc7280_wpss_resource = { · 1356 unmodified lines | |||
| 1457 | .ssctl_id = 0x19, | 1454 | .ssctl_id = 0x19, |
| 1458 | }; | 1455 | }; |
| 1459 | 1456 | ||
| 1457 | static const struct qcom_pas_data shikra_cdsp_resource = { | ||
| 1458 | .crash_reason_smem = 601, | ||
| 1459 | .firmware_name = "cdsp.mbn", | ||
| 1460 | .pas_id = 18, | ||
| 1461 | .minidump_id = 7, | ||
| 1462 | .auto_boot = true, | ||
| 1463 | .proxy_pd_names = (char *[]){ | ||
| 1464 | "cx", | ||
| 1465 | NULL | ||
| 1466 | }, | ||
| 1467 | .load_state = "cdsp", | ||
| 1468 | .ssr_name = "cdsp", | ||
| 1469 | .sysmon_name = "cdsp", | ||
| 1470 | .ssctl_id = 0x17, | ||
| 1471 | .smem_host_id = 5, | ||
| 1472 | }; | ||
| 1473 | |||
| 1474 | static const struct qcom_pas_data shikra_lpaicp_resource = { | ||
| 1475 | .crash_reason_smem = 682, | ||
| 1476 | .firmware_name = "lpaicp.mbn", | ||
| 1477 | .dtb_firmware_name = "lpaicp_dtb.mbn", | ||
| 1478 | .pas_id = 0x56, | ||
| 1479 | .dtb_pas_id = 0x57, | ||
| 1480 | .minidump_id = 0, | ||
| 1481 | .auto_boot = true, | ||
| 1482 | .ssr_name = "lpaicp", | ||
| 1483 | .sysmon_name = "lpaicp", | ||
| 1484 | }; | ||
| 1485 | |||
| 1486 | static const struct qcom_pas_data shikra_mpss_resource = { | ||
| 1487 | .crash_reason_smem = 421, | ||
| 1488 | .firmware_name = "qdsp6sw.mbn", | ||
| 1489 | .pas_id = 4, | ||
| 1490 | .minidump_id = 3, | ||
| 1491 | .auto_boot = false, | ||
| 1492 | .proxy_pd_names = (char *[]){ | ||
| 1493 | "cx", | ||
| 1494 | NULL | ||
| 1495 | }, | ||
| 1496 | .load_state = "modem", | ||
| 1497 | .ssr_name = "mpss", | ||
| 1498 | .sysmon_name = "modem", | ||
| 1499 | .ssctl_id = 0x12, | ||
| 1500 | }; | ||
| 1501 | |||
| 1460 | static const struct qcom_pas_data sm8650_cdsp_resource = { | 1502 | static const struct qcom_pas_data sm8650_cdsp_resource = { |
| 1461 | .crash_reason_smem = 601, | 1503 | .crash_reason_smem = 601, |
| 1462 | .firmware_name = "cdsp.mdt", | 1504 | .firmware_name = "cdsp.mdt", |
| @@ -1571,6 +1613,9 @@ static const struct of_device_id qcom_pas_of_match[] = { · 108 unmodified lines | |||
| 1571 | { .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init }, | 1613 | { .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init }, |
| 1572 | { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource }, | 1614 | { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource }, |
| 1573 | { .compatible = "qcom,sdx75-mpss-pas", .data = &sm8650_mpss_resource }, | 1615 | { .compatible = "qcom,sdx75-mpss-pas", .data = &sm8650_mpss_resource }, |
| 1616 | { .compatible = "qcom,shikra-cdsp-pas", .data = &shikra_cdsp_resource }, | ||
| 1617 | { .compatible = "qcom,shikra-lpaicp-pas", .data = &shikra_lpaicp_resource }, | ||
| 1618 | { .compatible = "qcom,shikra-mpss-pas", .data = &shikra_mpss_resource }, | ||
| 1574 | { .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init }, | 1619 | { .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init }, |
| 1575 | { .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init }, | 1620 | { .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init }, |
| 1576 | { .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource }, | 1621 | { .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource }, |
| @@ -96,7 +96,6 @@ struct wcss_data { · 95 unmodified lines | |||
| 96 | unsigned int crash_reason_smem; | 96 | unsigned int crash_reason_smem; |
| 97 | u32 version; | 97 | u32 version; |
| 98 | bool aon_reset_required; | 98 | bool aon_reset_required; |
| 99 | bool wcss_q6_reset_required; | ||
| 100 | const char *ssr_name; | 99 | const char *ssr_name; |
| 101 | const char *sysmon_name; | 100 | const char *sysmon_name; |
| 102 | int ssctl_id; | 101 | int ssctl_id; |
| @@ -134,7 +133,6 @@ struct q6v5_wcss { · 31 unmodified lines | |||
| 134 | struct reset_control *wcss_aon_reset; | 133 | struct reset_control *wcss_aon_reset; |
| 135 | struct reset_control *wcss_reset; | 134 | struct reset_control *wcss_reset; |
| 136 | struct reset_control *wcss_q6_reset; | 135 | struct reset_control *wcss_q6_reset; |
| 137 | struct reset_control *wcss_q6_bcr_reset; | ||
| 138 | 136 | ||
| 139 | struct qcom_q6v5 q6v5; | 137 | struct qcom_q6v5 q6v5; |
| 140 | 138 | ||
| @@ -309,7 +307,7 @@ static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss) · 168 unmodified lines | |||
| 309 | return ret; | 307 | return ret; |
| 310 | 308 | ||
| 311 | /* Remove reset to the WCNSS QDSP6SS */ | 309 | /* Remove reset to the WCNSS QDSP6SS */ |
| 312 | reset_control_deassert(wcss->wcss_q6_bcr_reset); | 310 | reset_control_deassert(wcss->wcss_q6_reset); |
| 313 | 311 | ||
| 314 | /* Enable Q6SSTOP_AHBFABRIC_CBCR clock */ | 312 | /* Enable Q6SSTOP_AHBFABRIC_CBCR clock */ |
| 315 | ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk); | 313 | ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk); |
| @@ -803,19 +801,10 @@ static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss, · 487 unmodified lines | |||
| 803 | return PTR_ERR(wcss->wcss_reset); | 801 | return PTR_ERR(wcss->wcss_reset); |
| 804 | } | 802 | } |
| 805 | 803 | ||
| 806 | if (desc->wcss_q6_reset_required) { | 804 | wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset"); |
| 807 | wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset"); | 805 | if (IS_ERR(wcss->wcss_q6_reset)) { |
| 808 | if (IS_ERR(wcss->wcss_q6_reset)) { | 806 | dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); |
| 809 | dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); | 807 | return PTR_ERR(wcss->wcss_q6_reset); |
| 810 | return PTR_ERR(wcss->wcss_q6_reset); | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | wcss->wcss_q6_bcr_reset = devm_reset_control_get_optional_exclusive(dev, | ||
| 815 | "wcss_q6_bcr_reset"); | ||
| 816 | if (IS_ERR(wcss->wcss_q6_bcr_reset)) { | ||
| 817 | dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n"); | ||
| 818 | return PTR_ERR(wcss->wcss_q6_bcr_reset); | ||
| 819 | } | 808 | } |
| 820 | 809 | ||
| 821 | return 0; | 810 | return 0; |
| @@ -1062,7 +1051,6 @@ static const struct wcss_data wcss_ipq8074_res_init = { · 240 unmodified lines | |||
| 1062 | .firmware_name = "IPQ8074/q6_fw.mdt", | 1051 | .firmware_name = "IPQ8074/q6_fw.mdt", |
| 1063 | .crash_reason_smem = WCSS_CRASH_REASON, | 1052 | .crash_reason_smem = WCSS_CRASH_REASON, |
| 1064 | .aon_reset_required = true, | 1053 | .aon_reset_required = true, |
| 1065 | .wcss_q6_reset_required = true, | ||
| 1066 | .ops = &q6v5_wcss_ipq8074_ops, | 1054 | .ops = &q6v5_wcss_ipq8074_ops, |
| 1067 | .requires_force_stop = true, | 1055 | .requires_force_stop = true, |
| 1068 | }; | 1056 | }; |
| @@ -1072,7 +1060,6 @@ static const struct wcss_data wcss_qcs404_res_init = { · 3 unmodified lines | |||
| 1072 | .firmware_name = "wcnss.mdt", | 1060 | .firmware_name = "wcnss.mdt", |
| 1073 | .version = WCSS_QCS404, | 1061 | .version = WCSS_QCS404, |
| 1074 | .aon_reset_required = false, | 1062 | .aon_reset_required = false, |
| 1075 | .wcss_q6_reset_required = false, | ||
| 1076 | .ssr_name = "mpss", | 1063 | .ssr_name = "mpss", |
| 1077 | .sysmon_name = "wcnss", | 1064 | .sysmon_name = "wcnss", |
| 1078 | .ssctl_id = 0x12, | 1065 | .ssctl_id = 0x12, |
| @@ -1011,60 +1011,55 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { · 1010 unmodified lines | |||
| 1011 | [RSC_VDEV] = rproc_handle_vdev, | 1011 | [RSC_VDEV] = rproc_handle_vdev, |
| 1012 | }; | 1012 | }; |
| 1013 | 1013 | ||
| 1014 | /* handle firmware resource entries before booting the remote processor */ | 1014 | struct rproc_rsc_cb_data { |
| 1015 | static int rproc_handle_resources(struct rproc *rproc, | 1015 | struct rproc *rproc; |
| 1016 | rproc_handle_resource_t handlers[RSC_LAST]) | 1016 | rproc_handle_resource_t *handlers; |
| 1017 | }; | ||
| 1018 | |||
| 1019 | static int rproc_handle_rsc_entry(u32 type, void *rsc, int offset, | ||
| 1020 | int avail, void *data) | ||
| 1017 | { | 1021 | { |
| 1022 | struct rproc_rsc_cb_data *d = data; | ||
| 1023 | struct rproc *rproc = d->rproc; | ||
| 1018 | struct device *dev = &rproc->dev; | 1024 | struct device *dev = &rproc->dev; |
| 1019 | rproc_handle_resource_t handler; | 1025 | rproc_handle_resource_t handler; |
| 1020 | int ret = 0, i; | 1026 | int ret; |
| 1021 | |||
| 1022 | if (!rproc->table_ptr) | ||
| 1023 | return 0; | ||
| 1024 | 1027 | ||
| 1025 | for (i = 0; i < rproc->table_ptr->num; i++) { | 1028 | dev_dbg(dev, "rsc: type %d\n", type); |
| 1026 | int offset = rproc->table_ptr->offset[i]; | ||
| 1027 | struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset; | ||
| 1028 | int avail = rproc->table_sz - offset - sizeof(*hdr); | ||
| 1029 | void *rsc = (void *)hdr + sizeof(*hdr); | ||
| 1030 | 1029 | ||
| 1031 | /* make sure table isn't truncated */ | 1030 | if (type >= RSC_VENDOR_START && type <= RSC_VENDOR_END) { |
| 1032 | if (avail < 0) { | 1031 | ret = rproc_handle_rsc(rproc, type, rsc, offset, avail); |
| 1033 | dev_err(dev, "rsc table is truncated\n"); | 1032 | if (ret == RSC_HANDLED) |
| 1034 | return -EINVAL; | 1033 | return 0; |
| 1035 | } | 1034 | if (ret < 0) |
| 1036 | 1035 | return ret; | |
| 1037 | dev_dbg(dev, "rsc: type %d\n", hdr->type); | 1036 | dev_warn(dev, "unsupported vendor resource %d\n", type); |
| 1037 | return 0; | ||
| 1038 | } | ||
| 1038 | 1039 | ||
| 1039 | if (hdr->type >= RSC_VENDOR_START && | 1040 | if (type >= RSC_LAST) { |
| 1040 | hdr->type <= RSC_VENDOR_END) { | 1041 | dev_warn(dev, "unsupported resource %d\n", type); |
| 1041 | ret = rproc_handle_rsc(rproc, hdr->type, rsc, | 1042 | return 0; |
| 1042 | offset + sizeof(*hdr), avail); | 1043 | } |
| 1043 | if (ret == RSC_HANDLED) | ||
| 1044 | continue; | ||
| 1045 | else if (ret < 0) | ||
| 1046 | break; | ||
| 1047 | 1044 | ||
| 1048 | dev_warn(dev, "unsupported vendor resource %d\n", | 1045 | handler = d->handlers[type]; |
| 1049 | hdr->type); | 1046 | if (!handler) |
| 1050 | continue; | 1047 | return 0; |
| 1051 | } | ||
| 1052 | 1048 | ||
| 1053 | if (hdr->type >= RSC_LAST) { | 1049 | return handler(rproc, rsc, offset, avail); |
| 1054 | dev_warn(dev, "unsupported resource %d\n", hdr->type); | 1050 | } |
| 1055 | continue; | ||
| 1056 | } | ||
| 1057 | 1051 | ||
| 1058 | handler = handlers[hdr->type]; | 1052 | /* handle firmware resource entries before booting the remote processor */ |
| 1059 | if (!handler) | 1053 | static int rproc_handle_resources(struct rproc *rproc, |
| 1060 | continue; | 1054 | rproc_handle_resource_t handlers[RSC_LAST]) |
| 1055 | { | ||
| 1056 | struct rproc_rsc_cb_data d = { .rproc = rproc, .handlers = handlers }; | ||
| 1061 | 1057 | ||
| 1062 | ret = handler(rproc, rsc, offset + sizeof(*hdr), avail); | 1058 | if (!rproc->table_ptr) |
| 1063 | if (ret) | 1059 | return 0; |
| 1064 | break; | ||
| 1065 | } | ||
| 1066 | 1060 | ||
| 1067 | return ret; | 1061 | return rsc_table_for_each_entry(rproc->table_ptr, rproc->table_sz, |
| 1062 | &rproc->dev, rproc_handle_rsc_entry, &d); | ||
| 1068 | } | 1063 | } |
| 1069 | 1064 | ||
| 1070 | static int rproc_prepare_subdevices(struct rproc *rproc) | 1065 | static int rproc_prepare_subdevices(struct rproc *rproc) |
| @@ -4,7 +4,6 @@ · 3 unmodified lines | |||
| 4 | * | 4 | * |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <dt-bindings/power/xlnx-zynqmp-power.h> | ||
| 8 | #include <linux/dma-mapping.h> | 7 | #include <linux/dma-mapping.h> |
| 9 | #include <linux/firmware/xlnx-zynqmp.h> | 8 | #include <linux/firmware/xlnx-zynqmp.h> |
| 10 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
| @@ -19,6 +18,11 @@ · 8 unmodified lines | |||
| 19 | 18 | ||
| 20 | #include "remoteproc_internal.h" | 19 | #include "remoteproc_internal.h" |
| 21 | 20 | ||
| 21 | #define PD_R5_0_ATCM 15 | ||
| 22 | #define PD_R5_0_BTCM 16 | ||
| 23 | #define PD_R5_1_ATCM 17 | ||
| 24 | #define PD_R5_1_BTCM 18 | ||
| 25 | |||
| 22 | /* IPI buffer MAX length */ | 26 | /* IPI buffer MAX length */ |
| 23 | #define IPI_BUF_LEN_MAX 32U | 27 | #define IPI_BUF_LEN_MAX 32U |
| 24 | 28 | ||
| @@ -899,17 +903,18 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = { · 874 unmodified lines | |||
| 899 | }; | 903 | }; |
| 900 | 904 | ||
| 901 | /** | 905 | /** |
| 902 | * zynqmp_r5_add_rproc_core() - Add core data to framework. | 906 | * zynqmp_r5_alloc_rproc_core() - alloc rproc core data structure |
| 903 | * Allocate and add struct rproc object for each r5f core | 907 | * Allocate struct rproc object for each r5f core |
| 904 | * This is called for each individual r5f core | 908 | * This is called for each individual r5f core |
| 905 | * | 909 | * |
| 906 | * @cdev: Device node of each r5 core | 910 | * @cdev: Device node of each r5 core |
| 907 | * | 911 | * |
| 908 | * Return: zynqmp_r5_core object for success else error code pointer | 912 | * Return: zynqmp_r5_core object for success else error code pointer |
| 909 | */ | 913 | */ |
| 910 | static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) | 914 | static struct zynqmp_r5_core *zynqmp_r5_alloc_rproc_core(struct device *cdev) |
| 911 | { | 915 | { |
| 912 | struct zynqmp_r5_core *r5_core; | 916 | struct zynqmp_r5_core *r5_core; |
| 917 | const char *fw_name = NULL; | ||
| 913 | struct rproc *r5_rproc; | 918 | struct rproc *r5_rproc; |
| 914 | int ret; | 919 | int ret; |
| 915 | 920 | ||
| @@ -918,10 +923,15 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) · 2 unmodified lines | |||
| 918 | if (ret) | 923 | if (ret) |
| 919 | return ERR_PTR(ret); | 924 | return ERR_PTR(ret); |
| 920 | 925 | ||
| 926 | ret = rproc_of_parse_firmware(cdev, 0, &fw_name); | ||
| 927 | if (ret < 0 && ret != -EINVAL) | ||
| 928 | return ERR_PTR(dev_err_probe(cdev, ret, | ||
| 929 | "failed to parse firmware-name\n")); | ||
| 930 | |||
| 921 | /* Allocate remoteproc instance */ | 931 | /* Allocate remoteproc instance */ |
| 922 | r5_rproc = rproc_alloc(cdev, dev_name(cdev), | 932 | r5_rproc = rproc_alloc(cdev, dev_name(cdev), |
| 923 | &zynqmp_r5_rproc_ops, | 933 | &zynqmp_r5_rproc_ops, |
| 924 | NULL, sizeof(struct zynqmp_r5_core)); | 934 | fw_name, sizeof(struct zynqmp_r5_core)); |
| 925 | if (!r5_rproc) { | 935 | if (!r5_rproc) { |
| 926 | dev_err(cdev, "failed to allocate memory for rproc instance\n"); | 936 | dev_err(cdev, "failed to allocate memory for rproc instance\n"); |
| 927 | return ERR_PTR(-ENOMEM); | 937 | return ERR_PTR(-ENOMEM); |
| @@ -932,6 +942,11 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) · 4 unmodified lines | |||
| 932 | r5_rproc->recovery_disabled = true; | 942 | r5_rproc->recovery_disabled = true; |
| 933 | r5_rproc->has_iommu = false; | 943 | r5_rproc->has_iommu = false; |
| 934 | r5_rproc->auto_boot = false; | 944 | r5_rproc->auto_boot = false; |
| 945 | |||
| 946 | /* attempt to boot automatically if the firmware-name is provided */ | ||
| 947 | if (fw_name) | ||
| 948 | r5_rproc->auto_boot = true; | ||
| 949 | |||
| 935 | r5_core = r5_rproc->priv; | 950 | r5_core = r5_rproc->priv; |
| 936 | r5_core->dev = cdev; | 951 | r5_core->dev = cdev; |
| 937 | r5_core->np = dev_of_node(cdev); | 952 | r5_core->np = dev_of_node(cdev); |
| @@ -941,23 +956,6 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) · 3 unmodified lines | |||
| 941 | goto free_rproc; | 956 | goto free_rproc; |
| 942 | } | 957 | } |
| 943 | 958 | ||
| 944 | /* Add R5 remoteproc core */ | ||
| 945 | ret = rproc_add(r5_rproc); | ||
| 946 | if (ret) { | ||
| 947 | dev_err(cdev, "failed to add r5 remoteproc\n"); | ||
| 948 | goto free_rproc; | ||
| 949 | } | ||
| 950 | |||
| 951 | /* | ||
| 952 | * If firmware is already available in the memory then move rproc state | ||
| 953 | * to DETACHED. Firmware can be preloaded via debugger or by any other | ||
| 954 | * agent (processors) in the system. | ||
| 955 | * If firmware isn't available in the memory and resource table isn't | ||
| 956 | * found, then rproc state remains OFFLINE. | ||
| 957 | */ | ||
| 958 | if (!zynqmp_r5_get_rsc_table_va(r5_core)) | ||
| 959 | r5_rproc->state = RPROC_DETACHED; | ||
| 960 | |||
| 961 | r5_core->rproc = r5_rproc; | 959 | r5_core->rproc = r5_rproc; |
| 962 | return r5_core; | 960 | return r5_core; |
| 963 | 961 | ||
| @@ -1210,6 +1208,7 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, · 246 unmodified lines | |||
| 1210 | { | 1208 | { |
| 1211 | struct device *dev = cluster->dev; | 1209 | struct device *dev = cluster->dev; |
| 1212 | struct zynqmp_r5_core *r5_core; | 1210 | struct zynqmp_r5_core *r5_core; |
| 1211 | u32 req, usage, status; | ||
| 1213 | int ret = -EINVAL, i; | 1212 | int ret = -EINVAL, i; |
| 1214 | 1213 | ||
| 1215 | r5_core = cluster->r5_cores[0]; | 1214 | r5_core = cluster->r5_cores[0]; |
| @@ -1255,6 +1254,42 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, · 39 unmodified lines | |||
| 1255 | ret = zynqmp_r5_get_sram_banks(r5_core); | 1254 | ret = zynqmp_r5_get_sram_banks(r5_core); |
| 1256 | if (ret) | 1255 | if (ret) |
| 1257 | return ret; | 1256 | return ret; |
| 1257 | |||
| 1258 | /* | ||
| 1259 | * It is possible that firmware is loaded into the memory, but | ||
| 1260 | * RPU (remote) is not running. In such case, RPU state will be | ||
| 1261 | * moved to RPROC_DETACHED wrongfully. To avoid it first make | ||
| 1262 | * sure RPU is power-on and out of reset before parsing for the | ||
| 1263 | * resource table. | ||
| 1264 | */ | ||
| 1265 | ret = zynqmp_pm_get_rpu_node_status(r5_core->pm_domain_id, | ||
| 1266 | &status, &req, &usage); | ||
| 1267 | if (ret) { | ||
| 1268 | dev_warn(r5_core->dev, | ||
| 1269 | "failed to get rpu node status, err %d\n", ret); | ||
| 1270 | continue; | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | /* | ||
| 1274 | * If RPU state is power on and out of reset i.e. running, then | ||
| 1275 | * assign RPROC_DETACHED state. If the RPU is not out of reset | ||
| 1276 | * then do not attempt to attach to the remote processor. | ||
| 1277 | */ | ||
| 1278 | if (status == PM_NODE_RUNNING) { | ||
| 1279 | /* | ||
| 1280 | * Not all the firmware that is running on the remote | ||
| 1281 | * core is expected to have the resource table. The | ||
| 1282 | * firmware might not use RPMsg at all, and in that case | ||
| 1283 | * resource table becomes irrelevant. However, we still | ||
| 1284 | * need to make sure that running core is not reported | ||
| 1285 | * as offline. so do not decide remote core state based | ||
| 1286 | * on the resource table availability | ||
| 1287 | */ | ||
| 1288 | if (zynqmp_r5_get_rsc_table_va(r5_core)) | ||
| 1289 | dev_dbg(r5_core->dev, "rsc tbl not found\n"); | ||
| 1290 | r5_core->rproc->state = RPROC_DETACHED; | ||
| 1291 | r5_core->rproc->auto_boot = true; | ||
| 1292 | } | ||
| 1258 | } | 1293 | } |
| 1259 | 1294 | ||
| 1260 | return 0; | 1295 | return 0; |
| @@ -1278,7 +1313,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) · 17 unmodified lines | |||
| 1278 | enum rpu_oper_mode fw_reg_val; | 1313 | enum rpu_oper_mode fw_reg_val; |
| 1279 | struct device **child_devs; | 1314 | struct device **child_devs; |
| 1280 | enum rpu_tcm_comb tcm_mode; | 1315 | enum rpu_tcm_comb tcm_mode; |
| 1281 | int core_count, ret, i; | 1316 | int core_count, ret, i, j; |
| 1282 | struct mbox_info *ipi; | 1317 | struct mbox_info *ipi; |
| 1283 | 1318 | ||
| 1284 | ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode); | 1319 | 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) · 79 unmodified lines | |||
| 1364 | child_devs[i] = &child_pdev->dev; | 1399 | child_devs[i] = &child_pdev->dev; |
| 1365 | 1400 | ||
| 1366 | /* create and add remoteproc instance of type struct rproc */ | 1401 | /* create and add remoteproc instance of type struct rproc */ |
| 1367 | r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev); | 1402 | r5_cores[i] = zynqmp_r5_alloc_rproc_core(&child_pdev->dev); |
| 1368 | if (IS_ERR(r5_cores[i])) { | 1403 | if (IS_ERR(r5_cores[i])) { |
| 1369 | ret = PTR_ERR(r5_cores[i]); | 1404 | ret = PTR_ERR(r5_cores[i]); |
| 1370 | r5_cores[i] = NULL; | 1405 | r5_cores[i] = NULL; |
| @@ -1409,16 +1444,31 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) · 38 unmodified lines | |||
| 1409 | goto release_r5_cores; | 1444 | goto release_r5_cores; |
| 1410 | } | 1445 | } |
| 1411 | 1446 | ||
| 1447 | for (j = 0; j < cluster->core_count; j++) { | ||
| 1448 | /* Add R5 remoteproc core */ | ||
| 1449 | ret = rproc_add(r5_cores[j]->rproc); | ||
| 1450 | if (ret) { | ||
| 1451 | dev_err_probe(r5_cores[j]->dev, ret, | ||
| 1452 | "failed to add remoteproc\n"); | ||
| 1453 | goto delete_r5_cores; | ||
| 1454 | } | ||
| 1455 | } | ||
| 1456 | |||
| 1412 | kfree(child_devs); | 1457 | kfree(child_devs); |
| 1413 | return 0; | 1458 | return 0; |
| 1414 | 1459 | ||
| 1460 | delete_r5_cores: | ||
| 1461 | i = core_count - 1; | ||
| 1462 | /* delete previous added rproc */ | ||
| 1463 | while (--j >= 0) | ||
| 1464 | rproc_del(r5_cores[j]->rproc); | ||
| 1465 | |||
| 1415 | release_r5_cores: | 1466 | release_r5_cores: |
| 1416 | while (i >= 0) { | 1467 | while (i >= 0) { |
| 1417 | put_device(child_devs[i]); | 1468 | put_device(child_devs[i]); |
| 1418 | if (r5_cores[i]) { | 1469 | if (r5_cores[i]) { |
| 1419 | zynqmp_r5_free_mbox(r5_cores[i]->ipi); | 1470 | zynqmp_r5_free_mbox(r5_cores[i]->ipi); |
| 1420 | of_reserved_mem_device_release(r5_cores[i]->dev); | 1471 | of_reserved_mem_device_release(r5_cores[i]->dev); |
| 1421 | rproc_del(r5_cores[i]->rproc); | ||
| 1422 | rproc_free(r5_cores[i]->rproc); | 1472 | rproc_free(r5_cores[i]->rproc); |
| 1423 | } | 1473 | } |
| 1424 | i--; | 1474 | i--; |
| @@ -542,6 +542,18 @@ enum pm_gem_config_type { · 541 unmodified lines | |||
| 542 | GEM_CONFIG_FIXED = 2, | 542 | GEM_CONFIG_FIXED = 2, |
| 543 | }; | 543 | }; |
| 544 | 544 | ||
| 545 | /** | ||
| 546 | * enum pm_node_status - Device node status provided by xilpm fw | ||
| 547 | * @PM_NODE_UNUSED: Device is not used | ||
| 548 | * @PM_NODE_RUNNING: Device is power-on and out of reset | ||
| 549 | * @PM_NODE_HALT: Device is power-on but in the reset state | ||
| 550 | */ | ||
| 551 | enum pm_node_status { | ||
| 552 | PM_NODE_UNUSED = 0, | ||
| 553 | PM_NODE_RUNNING = 1, | ||
| 554 | PM_NODE_HALT = 12, | ||
| 555 | }; | ||
| 556 | |||
| 545 | /** | 557 | /** |
| 546 | * struct zynqmp_pm_query_data - PM query data | 558 | * struct zynqmp_pm_query_data - PM query data |
| 547 | * @qid: query ID | 559 | * @qid: query ID |
| @@ -630,6 +642,8 @@ int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode); · 82 unmodified lines | |||
| 630 | int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode); | 642 | int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode); |
| 631 | int zynqmp_pm_get_node_status(const u32 node, u32 *const status, | 643 | int zynqmp_pm_get_node_status(const u32 node, u32 *const status, |
| 632 | u32 *const requirements, u32 *const usage); | 644 | u32 *const requirements, u32 *const usage); |
| 645 | int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status, | ||
| 646 | u32 *const requirements, u32 *const usage); | ||
| 633 | int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); | 647 | int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value); |
| 634 | int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, | 648 | int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, |
| 635 | u32 value); | 649 | u32 value); |
| @@ -939,6 +953,13 @@ static inline int zynqmp_pm_get_node_status(const u32 node, u32 *const status, · 303 unmodified lines | |||
| 939 | return -ENODEV; | 953 | return -ENODEV; |
| 940 | } | 954 | } |
| 941 | 955 | ||
| 956 | static inline int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status, | ||
| 957 | u32 *const requirements, | ||
| 958 | u32 *const usage) | ||
| 959 | { | ||
| 960 | return -ENODEV; | ||
| 961 | } | ||
| 962 | |||
| 942 | static inline int zynqmp_pm_set_sd_config(u32 node, | 963 | static inline int zynqmp_pm_set_sd_config(u32 node, |
| 943 | enum pm_sd_config_type config, | 964 | enum pm_sd_config_type config, |
| 944 | u32 value) | 965 | u32 value) |
| @@ -42,274 +42,7 @@ · 41 unmodified lines | |||
| 42 | #include <linux/completion.h> | 42 | #include <linux/completion.h> |
| 43 | #include <linux/idr.h> | 43 | #include <linux/idr.h> |
| 44 | #include <linux/of.h> | 44 | #include <linux/of.h> |
| 45 | 45 | #include <linux/rsc_table.h> | |
| 46 | /** | ||
| 47 | * struct resource_table - firmware resource table header | ||
| 48 | * @ver: version number | ||
| 49 | * @num: number of resource entries | ||
| 50 | * @reserved: reserved (must be zero) | ||
| 51 | * @offset: array of offsets pointing at the various resource entries | ||
| 52 | * | ||
| 53 | * A resource table is essentially a list of system resources required | ||
| 54 | * by the remote processor. It may also include configuration entries. | ||
| 55 | * If needed, the remote processor firmware should contain this table | ||
| 56 | * as a dedicated ".resource_table" ELF section. | ||
| 57 | * | ||
| 58 | * Some resources entries are mere announcements, where the host is informed | ||
| 59 | * of specific remoteproc configuration. Other entries require the host to | ||
| 60 | * do something (e.g. allocate a system resource). Sometimes a negotiation | ||
| 61 | * is expected, where the firmware requests a resource, and once allocated, | ||
| 62 | * the host should provide back its details (e.g. address of an allocated | ||
| 63 | * memory region). | ||
| 64 | * | ||
| 65 | * The header of the resource table, as expressed by this structure, | ||
| 66 | * contains a version number (should we need to change this format in the | ||
| 67 | * future), the number of available resource entries, and their offsets | ||
| 68 | * in the table. | ||
| 69 | * | ||
| 70 | * Immediately following this header are the resource entries themselves, | ||
| 71 | * each of which begins with a resource entry header (as described below). | ||
| 72 | */ | ||
| 73 | struct resource_table { | ||
| 74 | u32 ver; | ||
| 75 | u32 num; | ||
| 76 | u32 reserved[2]; | ||
| 77 | u32 offset[]; | ||
| 78 | } __packed; | ||
| 79 | |||
| 80 | /** | ||
| 81 | * struct fw_rsc_hdr - firmware resource entry header | ||
| 82 | * @type: resource type | ||
| 83 | * @data: resource data | ||
| 84 | * | ||
| 85 | * Every resource entry begins with a 'struct fw_rsc_hdr' header providing | ||
| 86 | * its @type. The content of the entry itself will immediately follow | ||
| 87 | * this header, and it should be parsed according to the resource type. | ||
| 88 | */ | ||
| 89 | struct fw_rsc_hdr { | ||
| 90 | u32 type; | ||
| 91 | u8 data[]; | ||
| 92 | } __packed; | ||
| 93 | |||
| 94 | /** | ||
| 95 | * enum fw_resource_type - types of resource entries | ||
| 96 | * | ||
| 97 | * @RSC_CARVEOUT: request for allocation of a physically contiguous | ||
| 98 | * memory region. | ||
| 99 | * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. | ||
| 100 | * @RSC_TRACE: announces the availability of a trace buffer into which | ||
| 101 | * the remote processor will be writing logs. | ||
| 102 | * @RSC_VDEV: declare support for a virtio device, and serve as its | ||
| 103 | * virtio header. | ||
| 104 | * @RSC_LAST: just keep this one at the end of standard resources | ||
| 105 | * @RSC_VENDOR_START: start of the vendor specific resource types range | ||
| 106 | * @RSC_VENDOR_END: end of the vendor specific resource types range | ||
| 107 | * | ||
| 108 | * For more details regarding a specific resource type, please see its | ||
| 109 | * dedicated structure below. | ||
| 110 | * | ||
| 111 | * Please note that these values are used as indices to the rproc_handle_rsc | ||
| 112 | * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to | ||
| 113 | * check the validity of an index before the lookup table is accessed, so | ||
| 114 | * please update it as needed. | ||
| 115 | */ | ||
| 116 | enum fw_resource_type { | ||
| 117 | RSC_CARVEOUT = 0, | ||
| 118 | RSC_DEVMEM = 1, | ||
| 119 | RSC_TRACE = 2, | ||
| 120 | RSC_VDEV = 3, | ||
| 121 | RSC_LAST = 4, | ||
| 122 | RSC_VENDOR_START = 128, | ||
| 123 | RSC_VENDOR_END = 512, | ||
| 124 | }; | ||
| 125 | |||
| 126 | #define FW_RSC_ADDR_ANY (-1) | ||
| 127 | |||
| 128 | /** | ||
| 129 | * struct fw_rsc_carveout - physically contiguous memory request | ||
| 130 | * @da: device address | ||
| 131 | * @pa: physical address | ||
| 132 | * @len: length (in bytes) | ||
| 133 | * @flags: iommu protection flags | ||
| 134 | * @reserved: reserved (must be zero) | ||
| 135 | * @name: human-readable name of the requested memory region | ||
| 136 | * | ||
| 137 | * This resource entry requests the host to allocate a physically contiguous | ||
| 138 | * memory region. | ||
| 139 | * | ||
| 140 | * These request entries should precede other firmware resource entries, | ||
| 141 | * as other entries might request placing other data objects inside | ||
| 142 | * these memory regions (e.g. data/code segments, trace resource entries, ...). | ||
| 143 | * | ||
| 144 | * Allocating memory this way helps utilizing the reserved physical memory | ||
| 145 | * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries | ||
| 146 | * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB | ||
| 147 | * pressure is important; it may have a substantial impact on performance. | ||
| 148 | * | ||
| 149 | * If the firmware is compiled with static addresses, then @da should specify | ||
| 150 | * the expected device address of this memory region. If @da is set to | ||
| 151 | * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then | ||
| 152 | * overwrite @da with the dynamically allocated address. | ||
| 153 | * | ||
| 154 | * We will always use @da to negotiate the device addresses, even if it | ||
| 155 | * isn't using an iommu. In that case, though, it will obviously contain | ||
| 156 | * physical addresses. | ||
| 157 | * | ||
| 158 | * Some remote processors needs to know the allocated physical address | ||
| 159 | * even if they do use an iommu. This is needed, e.g., if they control | ||
| 160 | * hardware accelerators which access the physical memory directly (this | ||
| 161 | * is the case with OMAP4 for instance). In that case, the host will | ||
| 162 | * overwrite @pa with the dynamically allocated physical address. | ||
| 163 | * Generally we don't want to expose physical addresses if we don't have to | ||
| 164 | * (remote processors are generally _not_ trusted), so we might want to | ||
| 165 | * change this to happen _only_ when explicitly required by the hardware. | ||
| 166 | * | ||
| 167 | * @flags is used to provide IOMMU protection flags, and @name should | ||
| 168 | * (optionally) contain a human readable name of this carveout region | ||
| 169 | * (mainly for debugging purposes). | ||
| 170 | */ | ||
| 171 | struct fw_rsc_carveout { | ||
| 172 | u32 da; | ||
| 173 | u32 pa; | ||
| 174 | u32 len; | ||
| 175 | u32 flags; | ||
| 176 | u32 reserved; | ||
| 177 | u8 name[32]; | ||
| 178 | } __packed; | ||
| 179 | |||
| 180 | /** | ||
| 181 | * struct fw_rsc_devmem - iommu mapping request | ||
| 182 | * @da: device address | ||
| 183 | * @pa: physical address | ||
| 184 | * @len: length (in bytes) | ||
| 185 | * @flags: iommu protection flags | ||
| 186 | * @reserved: reserved (must be zero) | ||
| 187 | * @name: human-readable name of the requested region to be mapped | ||
| 188 | * | ||
| 189 | * This resource entry requests the host to iommu map a physically contiguous | ||
| 190 | * memory region. This is needed in case the remote processor requires | ||
| 191 | * access to certain memory-based peripherals; _never_ use it to access | ||
| 192 | * regular memory. | ||
| 193 | * | ||
| 194 | * This is obviously only needed if the remote processor is accessing memory | ||
| 195 | * via an iommu. | ||
| 196 | * | ||
| 197 | * @da should specify the required device address, @pa should specify | ||
| 198 | * the physical address we want to map, @len should specify the size of | ||
| 199 | * the mapping and @flags is the IOMMU protection flags. As always, @name may | ||
| 200 | * (optionally) contain a human readable name of this mapping (mainly for | ||
| 201 | * debugging purposes). | ||
| 202 | * | ||
| 203 | * Note: at this point we just "trust" those devmem entries to contain valid | ||
| 204 | * physical addresses, but this isn't safe and will be changed: eventually we | ||
| 205 | * want remoteproc implementations to provide us ranges of physical addresses | ||
| 206 | * the firmware is allowed to request, and not allow firmwares to request | ||
| 207 | * access to physical addresses that are outside those ranges. | ||
| 208 | */ | ||
| 209 | struct fw_rsc_devmem { | ||
| 210 | u32 da; | ||
| 211 | u32 pa; | ||
| 212 | u32 len; | ||
| 213 | u32 flags; | ||
| 214 | u32 reserved; | ||
| 215 | u8 name[32]; | ||
| 216 | } __packed; | ||
| 217 | |||
| 218 | /** | ||
| 219 | * struct fw_rsc_trace - trace buffer declaration | ||
| 220 | * @da: device address | ||
| 221 | * @len: length (in bytes) | ||
| 222 | * @reserved: reserved (must be zero) | ||
| 223 | * @name: human-readable name of the trace buffer | ||
| 224 | * | ||
| 225 | * This resource entry provides the host information about a trace buffer | ||
| 226 | * into which the remote processor will write log messages. | ||
| 227 | * | ||
| 228 | * @da specifies the device address of the buffer, @len specifies | ||
| 229 | * its size, and @name may contain a human readable name of the trace buffer. | ||
| 230 | * | ||
| 231 | * After booting the remote processor, the trace buffers are exposed to the | ||
| 232 | * user via debugfs entries (called trace0, trace1, etc..). | ||
| 233 | */ | ||
| 234 | struct fw_rsc_trace { | ||
| 235 | u32 da; | ||
| 236 | u32 len; | ||
| 237 | u32 reserved; | ||
| 238 | u8 name[32]; | ||
| 239 | } __packed; | ||
| 240 | |||
| 241 | /** | ||
| 242 | * struct fw_rsc_vdev_vring - vring descriptor entry | ||
| 243 | * @da: device address | ||
| 244 | * @align: the alignment between the consumer and producer parts of the vring | ||
| 245 | * @num: num of buffers supported by this vring (must be power of two) | ||
| 246 | * @notifyid: a unique rproc-wide notify index for this vring. This notify | ||
| 247 | * index is used when kicking a remote processor, to let it know that this | ||
| 248 | * vring is triggered. | ||
| 249 | * @pa: physical address | ||
| 250 | * | ||
| 251 | * This descriptor is not a resource entry by itself; it is part of the | ||
| 252 | * vdev resource type (see below). | ||
| 253 | * | ||
| 254 | * Note that @da should either contain the device address where | ||
| 255 | * the remote processor is expecting the vring, or indicate that | ||
| 256 | * dynamically allocation of the vring's device address is supported. | ||
| 257 | */ | ||
| 258 | struct fw_rsc_vdev_vring { | ||
| 259 | u32 da; | ||
| 260 | u32 align; | ||
| 261 | u32 num; | ||
| 262 | u32 notifyid; | ||
| 263 | u32 pa; | ||
| 264 | } __packed; | ||
| 265 | |||
| 266 | /** | ||
| 267 | * struct fw_rsc_vdev - virtio device header | ||
| 268 | * @id: virtio device id (as in virtio_ids.h) | ||
| 269 | * @notifyid: a unique rproc-wide notify index for this vdev. This notify | ||
| 270 | * index is used when kicking a remote processor, to let it know that the | ||
| 271 | * status/features of this vdev have changes. | ||
| 272 | * @dfeatures: specifies the virtio device features supported by the firmware | ||
| 273 | * @gfeatures: a place holder used by the host to write back the | ||
| 274 | * negotiated features that are supported by both sides. | ||
| 275 | * @config_len: the size of the virtio config space of this vdev. The config | ||
| 276 | * space lies in the resource table immediate after this vdev header. | ||
| 277 | * @status: a place holder where the host will indicate its virtio progress. | ||
| 278 | * @num_of_vrings: indicates how many vrings are described in this vdev header | ||
| 279 | * @reserved: reserved (must be zero) | ||
| 280 | * @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. | ||
| 281 | * | ||
| 282 | * This resource is a virtio device header: it provides information about | ||
| 283 | * the vdev, and is then used by the host and its peer remote processors | ||
| 284 | * to negotiate and share certain virtio properties. | ||
| 285 | * | ||
| 286 | * By providing this resource entry, the firmware essentially asks remoteproc | ||
| 287 | * to statically allocate a vdev upon registration of the rproc (dynamic vdev | ||
| 288 | * allocation is not yet supported). | ||
| 289 | * | ||
| 290 | * Note: | ||
| 291 | * 1. unlike virtualization systems, the term 'host' here means | ||
| 292 | * the Linux side which is running remoteproc to control the remote | ||
| 293 | * processors. We use the name 'gfeatures' to comply with virtio's terms, | ||
| 294 | * though there isn't really any virtualized guest OS here: it's the host | ||
| 295 | * which is responsible for negotiating the final features. | ||
| 296 | * Yeah, it's a bit confusing. | ||
| 297 | * | ||
| 298 | * 2. immediately following this structure is the virtio config space for | ||
| 299 | * this vdev (which is specific to the vdev; for more info, read the virtio | ||
| 300 | * spec). The size of the config space is specified by @config_len. | ||
| 301 | */ | ||
| 302 | struct fw_rsc_vdev { | ||
| 303 | u32 id; | ||
| 304 | u32 notifyid; | ||
| 305 | u32 dfeatures; | ||
| 306 | u32 gfeatures; | ||
| 307 | u32 config_len; | ||
| 308 | u8 status; | ||
| 309 | u8 num_of_vrings; | ||
| 310 | u8 reserved[2]; | ||
| 311 | struct fw_rsc_vdev_vring vring[]; | ||
| 312 | } __packed; | ||
| 313 | 46 | ||
| 314 | struct rproc; | 47 | struct rproc; |
| 315 | 48 | ||
| @@ -0,0 +1,359 @@ | |||
| 1 | /* | ||
| 2 | * Resource table and its types data structure | ||
| 3 | * | ||
| 4 | * Copyright(c) 2011 Texas Instruments, Inc. | ||
| 5 | * Copyright(c) 2011 Google, Inc. | ||
| 6 | * All rights reserved. | ||
| 7 | * | ||
| 8 | * Redistribution and use in source and binary forms, with or without | ||
| 9 | * modification, are permitted provided that the following conditions | ||
| 10 | * are met: | ||
| 11 | * | ||
| 12 | * * Redistributions of source code must retain the above copyright | ||
| 13 | * notice, this list of conditions and the following disclaimer. | ||
| 14 | * * Redistributions in binary form must reproduce the above copyright | ||
| 15 | * notice, this list of conditions and the following disclaimer in | ||
| 16 | * the documentation and/or other materials provided with the | ||
| 17 | * distribution. | ||
| 18 | * * Neither the name Texas Instruments nor the names of its | ||
| 19 | * contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 33 | */ | ||
| 34 | |||
| 35 | #ifndef RSC_TABLE_H | ||
| 36 | #define RSC_TABLE_H | ||
| 37 | |||
| 38 | /** | ||
| 39 | * struct resource_table - firmware resource table header | ||
| 40 | * @ver: version number | ||
| 41 | * @num: number of resource entries | ||
| 42 | * @reserved: reserved (must be zero) | ||
| 43 | * @offset: array of offsets pointing at the various resource entries | ||
| 44 | * | ||
| 45 | * A resource table is essentially a list of system resources required | ||
| 46 | * by the remote processor. It may also include configuration entries. | ||
| 47 | * If needed, the remote processor firmware should contain this table | ||
| 48 | * as a dedicated ".resource_table" ELF section. | ||
| 49 | * | ||
| 50 | * Some resources entries are mere announcements, where the host is informed | ||
| 51 | * of specific remoteproc configuration. Other entries require the host to | ||
| 52 | * do something (e.g. allocate a system resource). Sometimes a negotiation | ||
| 53 | * is expected, where the firmware requests a resource, and once allocated, | ||
| 54 | * the host should provide back its details (e.g. address of an allocated | ||
| 55 | * memory region). | ||
| 56 | * | ||
| 57 | * The header of the resource table, as expressed by this structure, | ||
| 58 | * contains a version number (should we need to change this format in the | ||
| 59 | * future), the number of available resource entries, and their offsets | ||
| 60 | * in the table. | ||
| 61 | * | ||
| 62 | * Immediately following this header are the resource entries themselves, | ||
| 63 | * each of which begins with a resource entry header (as described below). | ||
| 64 | */ | ||
| 65 | struct resource_table { | ||
| 66 | u32 ver; | ||
| 67 | u32 num; | ||
| 68 | u32 reserved[2]; | ||
| 69 | u32 offset[]; | ||
| 70 | } __packed; | ||
| 71 | |||
| 72 | /** | ||
| 73 | * struct fw_rsc_hdr - firmware resource entry header | ||
| 74 | * @type: resource type | ||
| 75 | * @data: resource data | ||
| 76 | * | ||
| 77 | * Every resource entry begins with a 'struct fw_rsc_hdr' header providing | ||
| 78 | * its @type. The content of the entry itself will immediately follow | ||
| 79 | * this header, and it should be parsed according to the resource type. | ||
| 80 | */ | ||
| 81 | struct fw_rsc_hdr { | ||
| 82 | u32 type; | ||
| 83 | u8 data[]; | ||
| 84 | } __packed; | ||
| 85 | |||
| 86 | /** | ||
| 87 | * enum fw_resource_type - types of resource entries | ||
| 88 | * | ||
| 89 | * @RSC_CARVEOUT: request for allocation of a physically contiguous | ||
| 90 | * memory region. | ||
| 91 | * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. | ||
| 92 | * @RSC_TRACE: announces the availability of a trace buffer into which | ||
| 93 | * the remote processor will be writing logs. | ||
| 94 | * @RSC_VDEV: declare support for a virtio device, and serve as its | ||
| 95 | * virtio header. | ||
| 96 | * @RSC_LAST: just keep this one at the end of standard resources | ||
| 97 | * @RSC_VENDOR_START: start of the vendor specific resource types range | ||
| 98 | * @RSC_VENDOR_END: end of the vendor specific resource types range | ||
| 99 | * | ||
| 100 | * For more details regarding a specific resource type, please see its | ||
| 101 | * dedicated structure below. | ||
| 102 | * | ||
| 103 | * Please note that these values are used as indices to the rproc_handle_rsc | ||
| 104 | * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to | ||
| 105 | * check the validity of an index before the lookup table is accessed, so | ||
| 106 | * please update it as needed. | ||
| 107 | */ | ||
| 108 | enum fw_resource_type { | ||
| 109 | RSC_CARVEOUT = 0, | ||
| 110 | RSC_DEVMEM = 1, | ||
| 111 | RSC_TRACE = 2, | ||
| 112 | RSC_VDEV = 3, | ||
| 113 | RSC_LAST = 4, | ||
| 114 | RSC_VENDOR_START = 128, | ||
| 115 | RSC_VENDOR_END = 512, | ||
| 116 | }; | ||
| 117 | |||
| 118 | #define FW_RSC_ADDR_ANY (-1) | ||
| 119 | |||
| 120 | /** | ||
| 121 | * struct fw_rsc_carveout - physically contiguous memory request | ||
| 122 | * @da: device address | ||
| 123 | * @pa: physical address | ||
| 124 | * @len: length (in bytes) | ||
| 125 | * @flags: iommu protection flags | ||
| 126 | * @reserved: reserved (must be zero) | ||
| 127 | * @name: human-readable name of the requested memory region | ||
| 128 | * | ||
| 129 | * This resource entry requests the host to allocate a physically contiguous | ||
| 130 | * memory region. | ||
| 131 | * | ||
| 132 | * These request entries should precede other firmware resource entries, | ||
| 133 | * as other entries might request placing other data objects inside | ||
| 134 | * these memory regions (e.g. data/code segments, trace resource entries, ...). | ||
| 135 | * | ||
| 136 | * Allocating memory this way helps utilizing the reserved physical memory | ||
| 137 | * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries | ||
| 138 | * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB | ||
| 139 | * pressure is important; it may have a substantial impact on performance. | ||
| 140 | * | ||
| 141 | * If the firmware is compiled with static addresses, then @da should specify | ||
| 142 | * the expected device address of this memory region. If @da is set to | ||
| 143 | * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then | ||
| 144 | * overwrite @da with the dynamically allocated address. | ||
| 145 | * | ||
| 146 | * We will always use @da to negotiate the device addresses, even if it | ||
| 147 | * isn't using an iommu. In that case, though, it will obviously contain | ||
| 148 | * physical addresses. | ||
| 149 | * | ||
| 150 | * Some remote processors needs to know the allocated physical address | ||
| 151 | * even if they do use an iommu. This is needed, e.g., if they control | ||
| 152 | * hardware accelerators which access the physical memory directly (this | ||
| 153 | * is the case with OMAP4 for instance). In that case, the host will | ||
| 154 | * overwrite @pa with the dynamically allocated physical address. | ||
| 155 | * Generally we don't want to expose physical addresses if we don't have to | ||
| 156 | * (remote processors are generally _not_ trusted), so we might want to | ||
| 157 | * change this to happen _only_ when explicitly required by the hardware. | ||
| 158 | * | ||
| 159 | * @flags is used to provide IOMMU protection flags, and @name should | ||
| 160 | * (optionally) contain a human readable name of this carveout region | ||
| 161 | * (mainly for debugging purposes). | ||
| 162 | */ | ||
| 163 | struct fw_rsc_carveout { | ||
| 164 | u32 da; | ||
| 165 | u32 pa; | ||
| 166 | u32 len; | ||
| 167 | u32 flags; | ||
| 168 | u32 reserved; | ||
| 169 | u8 name[32]; | ||
| 170 | } __packed; | ||
| 171 | |||
| 172 | /** | ||
| 173 | * struct fw_rsc_devmem - iommu mapping request | ||
| 174 | * @da: device address | ||
| 175 | * @pa: physical address | ||
| 176 | * @len: length (in bytes) | ||
| 177 | * @flags: iommu protection flags | ||
| 178 | * @reserved: reserved (must be zero) | ||
| 179 | * @name: human-readable name of the requested region to be mapped | ||
| 180 | * | ||
| 181 | * This resource entry requests the host to iommu map a physically contiguous | ||
| 182 | * memory region. This is needed in case the remote processor requires | ||
| 183 | * access to certain memory-based peripherals; _never_ use it to access | ||
| 184 | * regular memory. | ||
| 185 | * | ||
| 186 | * This is obviously only needed if the remote processor is accessing memory | ||
| 187 | * via an iommu. | ||
| 188 | * | ||
| 189 | * @da should specify the required device address, @pa should specify | ||
| 190 | * the physical address we want to map, @len should specify the size of | ||
| 191 | * the mapping and @flags is the IOMMU protection flags. As always, @name may | ||
| 192 | * (optionally) contain a human readable name of this mapping (mainly for | ||
| 193 | * debugging purposes). | ||
| 194 | * | ||
| 195 | * Note: at this point we just "trust" those devmem entries to contain valid | ||
| 196 | * physical addresses, but this isn't safe and will be changed: eventually we | ||
| 197 | * want remoteproc implementations to provide us ranges of physical addresses | ||
| 198 | * the firmware is allowed to request, and not allow firmwares to request | ||
| 199 | * access to physical addresses that are outside those ranges. | ||
| 200 | */ | ||
| 201 | struct fw_rsc_devmem { | ||
| 202 | u32 da; | ||
| 203 | u32 pa; | ||
| 204 | u32 len; | ||
| 205 | u32 flags; | ||
| 206 | u32 reserved; | ||
| 207 | u8 name[32]; | ||
| 208 | } __packed; | ||
| 209 | |||
| 210 | /** | ||
| 211 | * struct fw_rsc_trace - trace buffer declaration | ||
| 212 | * @da: device address | ||
| 213 | * @len: length (in bytes) | ||
| 214 | * @reserved: reserved (must be zero) | ||
| 215 | * @name: human-readable name of the trace buffer | ||
| 216 | * | ||
| 217 | * This resource entry provides the host information about a trace buffer | ||
| 218 | * into which the remote processor will write log messages. | ||
| 219 | * | ||
| 220 | * @da specifies the device address of the buffer, @len specifies | ||
| 221 | * its size, and @name may contain a human readable name of the trace buffer. | ||
| 222 | * | ||
| 223 | * After booting the remote processor, the trace buffers are exposed to the | ||
| 224 | * user via debugfs entries (called trace0, trace1, etc..). | ||
| 225 | */ | ||
| 226 | struct fw_rsc_trace { | ||
| 227 | u32 da; | ||
| 228 | u32 len; | ||
| 229 | u32 reserved; | ||
| 230 | u8 name[32]; | ||
| 231 | } __packed; | ||
| 232 | |||
| 233 | /** | ||
| 234 | * struct fw_rsc_vdev_vring - vring descriptor entry | ||
| 235 | * @da: device address | ||
| 236 | * @align: the alignment between the consumer and producer parts of the vring | ||
| 237 | * @num: num of buffers supported by this vring (must be power of two) | ||
| 238 | * @notifyid: a unique rproc-wide notify index for this vring. This notify | ||
| 239 | * index is used when kicking a remote processor, to let it know that this | ||
| 240 | * vring is triggered. | ||
| 241 | * @pa: physical address | ||
| 242 | * | ||
| 243 | * This descriptor is not a resource entry by itself; it is part of the | ||
| 244 | * vdev resource type (see below). | ||
| 245 | * | ||
| 246 | * Note that @da should either contain the device address where | ||
| 247 | * the remote processor is expecting the vring, or indicate that | ||
| 248 | * dynamically allocation of the vring's device address is supported. | ||
| 249 | */ | ||
| 250 | struct fw_rsc_vdev_vring { | ||
| 251 | u32 da; | ||
| 252 | u32 align; | ||
| 253 | u32 num; | ||
| 254 | u32 notifyid; | ||
| 255 | u32 pa; | ||
| 256 | } __packed; | ||
| 257 | |||
| 258 | /** | ||
| 259 | * struct fw_rsc_vdev - virtio device header | ||
| 260 | * @id: virtio device id (as in virtio_ids.h) | ||
| 261 | * @notifyid: a unique rproc-wide notify index for this vdev. This notify | ||
| 262 | * index is used when kicking a remote processor, to let it know that the | ||
| 263 | * status/features of this vdev have changes. | ||
| 264 | * @dfeatures: specifies the virtio device features supported by the firmware | ||
| 265 | * @gfeatures: a place holder used by the host to write back the | ||
| 266 | * negotiated features that are supported by both sides. | ||
| 267 | * @config_len: the size of the virtio config space of this vdev. The config | ||
| 268 | * space lies in the resource table immediate after this vdev header. | ||
| 269 | * @status: a place holder where the host will indicate its virtio progress. | ||
| 270 | * @num_of_vrings: indicates how many vrings are described in this vdev header | ||
| 271 | * @reserved: reserved (must be zero) | ||
| 272 | * @vring: an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. | ||
| 273 | * | ||
| 274 | * This resource is a virtio device header: it provides information about | ||
| 275 | * the vdev, and is then used by the host and its peer remote processors | ||
| 276 | * to negotiate and share certain virtio properties. | ||
| 277 | * | ||
| 278 | * By providing this resource entry, the firmware essentially asks remoteproc | ||
| 279 | * to statically allocate a vdev upon registration of the rproc (dynamic vdev | ||
| 280 | * allocation is not yet supported). | ||
| 281 | * | ||
| 282 | * Note: | ||
| 283 | * 1. unlike virtualization systems, the term 'host' here means | ||
| 284 | * the Linux side which is running remoteproc to control the remote | ||
| 285 | * processors. We use the name 'gfeatures' to comply with virtio's terms, | ||
| 286 | * though there isn't really any virtualized guest OS here: it's the host | ||
| 287 | * which is responsible for negotiating the final features. | ||
| 288 | * Yeah, it's a bit confusing. | ||
| 289 | * | ||
| 290 | * 2. immediately following this structure is the virtio config space for | ||
| 291 | * this vdev (which is specific to the vdev; for more info, read the virtio | ||
| 292 | * spec). The size of the config space is specified by @config_len. | ||
| 293 | */ | ||
| 294 | struct fw_rsc_vdev { | ||
| 295 | u32 id; | ||
| 296 | u32 notifyid; | ||
| 297 | u32 dfeatures; | ||
| 298 | u32 gfeatures; | ||
| 299 | u32 config_len; | ||
| 300 | u8 status; | ||
| 301 | u8 num_of_vrings; | ||
| 302 | u8 reserved[2]; | ||
| 303 | struct fw_rsc_vdev_vring vring[]; | ||
| 304 | } __packed; | ||
| 305 | |||
| 306 | /** | ||
| 307 | * rsc_table_for_each_entry() - iterate over all entries in a resource table | ||
| 308 | * @table: pointer to the resource table | ||
| 309 | * @table_sz: total size of the table buffer in bytes | ||
| 310 | * @dev: device used for error logging | ||
| 311 | * @cb: callback invoked for each entry: | ||
| 312 | * @type - value from enum fw_resource_type | ||
| 313 | * @rsc - pointer to the entry payload (past struct fw_rsc_hdr) | ||
| 314 | * @offset - byte offset of the payload within the table; callers | ||
| 315 | * that write back into the table (e.g. to record a | ||
| 316 | * dynamically allocated address) use this to locate the | ||
| 317 | * entry for later update | ||
| 318 | * @avail - bytes available in the payload | ||
| 319 | * @data - caller-supplied private pointer | ||
| 320 | * Return 0 to continue iteration, non-zero to stop. | ||
| 321 | * @data: private pointer forwarded to @cb on every call | ||
| 322 | * | ||
| 323 | * Iterates over every resource entry in @table, performing the standard | ||
| 324 | * truncation check, and invokes @cb for each one. Iteration stops on the | ||
| 325 | * first non-zero return from @cb or on a malformed table. | ||
| 326 | * | ||
| 327 | * Returns 0 after a complete iteration, -EINVAL if the table is truncated, | ||
| 328 | * or the first non-zero value returned by @cb. | ||
| 329 | */ | ||
| 330 | static inline int rsc_table_for_each_entry(struct resource_table *table, | ||
| 331 | size_t table_sz, | ||
| 332 | struct device *dev, | ||
| 333 | int (*cb)(u32 type, void *rsc, | ||
| 334 | int offset, int avail, | ||
| 335 | void *data), | ||
| 336 | void *data) { | ||
| 337 | int i, ret; | ||
| 338 | |||
| 339 | for (i = 0; i < table->num; i++) { | ||
| 340 | int offset = table->offset[i]; | ||
| 341 | struct fw_rsc_hdr *hdr = (void *)table + offset; | ||
| 342 | int avail = table_sz - offset - sizeof(*hdr); | ||
| 343 | int rsc_offset = offset + sizeof(*hdr); | ||
| 344 | void *rsc = (void *)hdr + sizeof(*hdr); | ||
| 345 | |||
| 346 | if (avail < 0) { | ||
| 347 | dev_err(dev, "rsc table is truncated\n"); | ||
| 348 | return -EINVAL; | ||
| 349 | } | ||
| 350 | |||
| 351 | ret = cb(hdr->type, rsc, rsc_offset, avail, data); | ||
| 352 | if (ret) | ||
| 353 | return ret; | ||
| 354 | } | ||
| 355 | |||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | #endif /* RSC_TABLE_H */ | ||