Merge tag 'rproc-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux

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
This commit is contained in:
Linus Torvalds
2026-06-20 23:26:18 -07:00
17 changed files with 861 additions and 370 deletions
@@ -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:
@@ -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
@@ -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";
};
};
@@ -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
@@ -128,6 +128,10 @@ patternProperties:
- description: vring1
additionalItems: true
firmware-name:
maxItems: 1
description: default firmware to load
required:
- compatible
- reg
+28
View File
@@ -1450,6 +1450,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
+1 -2
View File
@@ -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
+91 -4
View File
@@ -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 },
{},
};
+2
View File
@@ -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 */
+10 -4
View File
@@ -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,
+48 -3
View File
@@ -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 },
+5 -18
View File
@@ -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,
+41 -46
View File
@@ -1011,60 +1011,55 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
[RSC_VDEV] = rproc_handle_vdev,
};
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;
dev_dbg(dev, "rsc: type %d\n", 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 (type >= RSC_LAST) {
dev_warn(dev, "unsupported resource %d\n", type);
return 0;
}
handler = d->handlers[type];
if (!handler)
return 0;
return handler(rproc, rsc, offset, avail);
}
/* 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 device *dev = &rproc->dev;
rproc_handle_resource_t handler;
int ret = 0, i;
struct rproc_rsc_cb_data d = { .rproc = rproc, .handlers = handlers };
if (!rproc->table_ptr)
return 0;
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);
/* 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 (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;
dev_warn(dev, "unsupported vendor resource %d\n",
hdr->type);
continue;
}
if (hdr->type >= RSC_LAST) {
dev_warn(dev, "unsupported resource %d\n", hdr->type);
continue;
}
handler = handlers[hdr->type];
if (!handler)
continue;
ret = handler(rproc, rsc, offset + sizeof(*hdr), avail);
if (ret)
break;
}
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)
+75 -25
View File
@@ -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--;
+21
View File
@@ -542,6 +542,18 @@ enum pm_gem_config_type {
GEM_CONFIG_FIXED = 2,
};
/**
* 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
@@ -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)
+1 -268
View File
@@ -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;
+359
View File
@@ -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 */