From a73d9468c802359c44ca9ba0d7b171f4a1548e44 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 19 Dec 2016 10:22:50 +0100 Subject: [PATCH 01/27] remoteproc: add some kind of help Top level config option without any kind of help... is kind of strange. Remote processors could also mean some kind of distributed computing... Signed-off-by: Pavel Machek Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 8f9cf0bc571c..a5e888043f1f 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -7,6 +7,9 @@ config REMOTEPROC select FW_LOADER select VIRTIO select VIRTUALIZATION + help + Support for remote processors (such as DSP coprocessors). These + are mainly used on embedded systems. if REMOTEPROC @@ -25,11 +28,11 @@ config OMAP_REMOTEPROC Currently only supported on OMAP4. - Usually you want to say y here, in order to enable multimedia + Usually you want to say Y here, in order to enable multimedia use-cases to run on your platform (multimedia codecs are offloaded to remote DSP processors using this framework). - It's safe to say n here if you're not interested in multimedia + It's safe to say N here if you're not interested in multimedia offloading or just want a bare minimum kernel. config WKUP_M3_RPROC From 7a8ffe1fcaf89bb7d2588b98cba3163ee7d9db7a Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Fri, 30 Dec 2016 19:24:00 +0530 Subject: [PATCH 02/27] remoteproc: qcom: Compatible string based private resource initialization. MSS rproc loader need chip specific resources initialization during probe to load and boot modem firmware, this need compatible string based differentiation in resources to be initialized. This patch add and provide a template struct whose fields represent all those resources which are needed to load and boot modem fw and which may differ from chip to chip. This patch also add new compatible string for msm8916, msm8974 platform. Signed-off-by: Avaneesh Kumar Dwivedi Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,q6v5.txt | 4 ++- drivers/remoteproc/qcom_q6v5_pil.c | 25 ++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt index 57cb49ec55ca..92347fe6890e 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt @@ -7,7 +7,9 @@ on the Qualcomm Hexagon core. Usage: required Value type: Definition: must be one of: - "qcom,q6v5-pil" + "qcom,q6v5-pil", + "qcom,msm8916-mss-pil", + "qcom,msm8974-mss-pil" - reg: Usage: required diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index b08989b48df7..1bebe88fdb62 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,6 @@ #include -#define MBA_FIRMWARE_NAME "mba.b00" #define MPSS_FIRMWARE_NAME "modem.mdt" #define MPSS_CRASH_REASON_SMEM 421 @@ -93,6 +93,10 @@ #define QDSS_BHS_ON BIT(21) #define QDSS_LDO_BYP BIT(22) +struct rproc_hexagon_res { + const char *hexagon_mba_image; +}; + struct q6v5 { struct device *dev; struct rproc *rproc; @@ -805,12 +809,17 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) static int q6v5_probe(struct platform_device *pdev) { + const struct rproc_hexagon_res *desc; struct q6v5 *qproc; struct rproc *rproc; int ret; + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops, - MBA_FIRMWARE_NAME, sizeof(*qproc)); + desc->hexagon_mba_image, sizeof(*qproc)); if (!rproc) { dev_err(&pdev->dev, "failed to allocate rproc\n"); return -ENOMEM; @@ -890,8 +899,18 @@ static int q6v5_remove(struct platform_device *pdev) return 0; } +static const struct rproc_hexagon_res msm8916_mss = { + .hexagon_mba_image = "mba.mbn", +}; + +static const struct rproc_hexagon_res msm8974_mss = { + .hexagon_mba_image = "mba.b00", +}; + static const struct of_device_id q6v5_of_match[] = { - { .compatible = "qcom,q6v5-pil", }, + { .compatible = "qcom,q6v5-pil", .data = &msm8916_mss}, + { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss}, + { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss}, { }, }; MODULE_DEVICE_TABLE(of, q6v5_of_match); From 39b2410bdcdbc2f7a96cde9966d8eabe861e6d3c Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Fri, 30 Dec 2016 19:24:01 +0530 Subject: [PATCH 03/27] remoteproc: qcom: Initialize and enable proxy and active clocks. Certain clocks need voting by rproc on behalf of hexagon only during restart operation but certain clocks need to be voted till hexagon is up, these clocks are identified as proxy and active clocks respectively. This patch provide interface to initialize, enable and disable proxy and active clocks separately. Signed-off-by: Avaneesh Kumar Dwivedi [bjorn: dropped disable of proxy clocks on stop] Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pil.c | 155 +++++++++++++++++++++-------- 1 file changed, 111 insertions(+), 44 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 1bebe88fdb62..991193596d9e 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -95,6 +95,8 @@ struct rproc_hexagon_res { const char *hexagon_mba_image; + char **proxy_clk_names; + char **active_clk_names; }; struct q6v5 { @@ -114,11 +116,13 @@ struct q6v5 { struct qcom_smem_state *state; unsigned stop_bit; + struct clk *active_clks[8]; + struct clk *proxy_clks[4]; + int active_clk_count; + int proxy_clk_count; + struct regulator_bulk_data supply[4]; - struct clk *ahb_clk; - struct clk *axi_clk; - struct clk *rom_clk; struct completion start_done; struct completion stop_done; @@ -193,6 +197,37 @@ static void q6v5_regulator_disable(struct q6v5 *qproc) regulator_set_voltage(mss, 0, 1150000); } +static int q6v5_clk_enable(struct device *dev, + struct clk **clks, int count) +{ + int rc; + int i; + + for (i = 0; i < count; i++) { + rc = clk_prepare_enable(clks[i]); + if (rc) { + dev_err(dev, "Clock enable failed\n"); + goto err; + } + } + + return 0; +err: + for (i--; i >= 0; i--) + clk_disable_unprepare(clks[i]); + + return rc; +} + +static void q6v5_clk_disable(struct device *dev, + struct clk **clks, int count) +{ + int i; + + for (i = 0; i < count; i++) + clk_disable_unprepare(clks[i]); +} + static int q6v5_load(struct rproc *rproc, const struct firmware *fw) { struct q6v5 *qproc = rproc->priv; @@ -488,23 +523,24 @@ static int q6v5_start(struct rproc *rproc) return ret; } + ret = q6v5_clk_enable(qproc->dev, qproc->proxy_clks, + qproc->proxy_clk_count); + if (ret) { + dev_err(qproc->dev, "failed to enable proxy clocks\n"); + goto disable_vdd; + } ret = reset_control_deassert(qproc->mss_restart); if (ret) { dev_err(qproc->dev, "failed to deassert mss restart\n"); - goto disable_vdd; + goto disable_proxy_clk; } - ret = clk_prepare_enable(qproc->ahb_clk); - if (ret) + ret = q6v5_clk_enable(qproc->dev, qproc->active_clks, + qproc->active_clk_count); + if (ret) { + dev_err(qproc->dev, "failed to enable clocks\n"); goto assert_reset; - - ret = clk_prepare_enable(qproc->axi_clk); - if (ret) - goto disable_ahb_clk; - - ret = clk_prepare_enable(qproc->rom_clk); - if (ret) - goto disable_axi_clk; + } writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); @@ -539,7 +575,8 @@ static int q6v5_start(struct rproc *rproc) qproc->running = true; - /* TODO: All done, release the handover resources */ + q6v5_clk_disable(qproc->dev, qproc->proxy_clks, + qproc->proxy_clk_count); return 0; @@ -547,14 +584,13 @@ halt_axi_ports: q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); - - clk_disable_unprepare(qproc->rom_clk); -disable_axi_clk: - clk_disable_unprepare(qproc->axi_clk); -disable_ahb_clk: - clk_disable_unprepare(qproc->ahb_clk); + q6v5_clk_disable(qproc->dev, qproc->active_clks, + qproc->active_clk_count); assert_reset: reset_control_assert(qproc->mss_restart); +disable_proxy_clk: + q6v5_clk_disable(qproc->dev, qproc->proxy_clks, + qproc->proxy_clk_count); disable_vdd: q6v5_regulator_disable(qproc); @@ -583,9 +619,8 @@ static int q6v5_stop(struct rproc *rproc) q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); reset_control_assert(qproc->mss_restart); - clk_disable_unprepare(qproc->rom_clk); - clk_disable_unprepare(qproc->axi_clk); - clk_disable_unprepare(qproc->ahb_clk); + q6v5_clk_disable(qproc->dev, qproc->active_clks, + qproc->active_clk_count); q6v5_regulator_disable(qproc); return 0; @@ -706,27 +741,27 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) return 0; } -static int q6v5_init_clocks(struct q6v5 *qproc) +static int q6v5_init_clocks(struct device *dev, struct clk **clks, + char **clk_names) { - qproc->ahb_clk = devm_clk_get(qproc->dev, "iface"); - if (IS_ERR(qproc->ahb_clk)) { - dev_err(qproc->dev, "failed to get iface clock\n"); - return PTR_ERR(qproc->ahb_clk); + int i; + + if (!clk_names) + return 0; + + for (i = 0; clk_names[i]; i++) { + clks[i] = devm_clk_get(dev, clk_names[i]); + if (IS_ERR(clks[i])) { + int rc = PTR_ERR(clks[i]); + + if (rc != -EPROBE_DEFER) + dev_err(dev, "Failed to get %s clock\n", + clk_names[i]); + return rc; + } } - qproc->axi_clk = devm_clk_get(qproc->dev, "bus"); - if (IS_ERR(qproc->axi_clk)) { - dev_err(qproc->dev, "failed to get bus clock\n"); - return PTR_ERR(qproc->axi_clk); - } - - qproc->rom_clk = devm_clk_get(qproc->dev, "mem"); - if (IS_ERR(qproc->rom_clk)) { - dev_err(qproc->dev, "failed to get mem clock\n"); - return PTR_ERR(qproc->rom_clk); - } - - return 0; + return i; } static int q6v5_init_reset(struct q6v5 *qproc) @@ -843,9 +878,21 @@ static int q6v5_probe(struct platform_device *pdev) if (ret) goto free_rproc; - ret = q6v5_init_clocks(qproc); - if (ret) + ret = q6v5_init_clocks(&pdev->dev, qproc->proxy_clks, + desc->proxy_clk_names); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get proxy clocks.\n"); goto free_rproc; + } + qproc->proxy_clk_count = ret; + + ret = q6v5_init_clocks(&pdev->dev, qproc->active_clks, + desc->active_clk_names); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get active clocks.\n"); + goto free_rproc; + } + qproc->active_clk_count = ret; ret = q6v5_regulator_init(qproc); if (ret) @@ -901,10 +948,30 @@ static int q6v5_remove(struct platform_device *pdev) static const struct rproc_hexagon_res msm8916_mss = { .hexagon_mba_image = "mba.mbn", + .proxy_clk_names = (char*[]){ + "xo", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "bus", + "mem", + NULL + }, }; static const struct rproc_hexagon_res msm8974_mss = { .hexagon_mba_image = "mba.b00", + .proxy_clk_names = (char*[]){ + "xo", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "bus", + "mem", + NULL + }, }; static const struct of_device_id q6v5_of_match[] = { From 19f902b53b47327e87daecacf0aea450b990f33e Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Fri, 30 Dec 2016 19:24:02 +0530 Subject: [PATCH 04/27] remoteproc: qcom: Initialize and enable proxy and active regulators. Certain regulators need voting by rproc on behalf of hexagon only during restart operation but certain regulator need to be voted till hexagon is up, these regulators are identified as proxy and active regulators respectively. This patch provide interface to initialize, enable and disable proxy and active regulators separately. Signed-off-by: Avaneesh Kumar Dwivedi [bjorn: dropped disable of proxy regulators from stop] Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pil.c | 229 ++++++++++++++++++++++------- 1 file changed, 174 insertions(+), 55 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 991193596d9e..9a5149573298 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -93,8 +93,22 @@ #define QDSS_BHS_ON BIT(21) #define QDSS_LDO_BYP BIT(22) +struct reg_info { + struct regulator *reg; + int uV; + int uA; +}; + +struct qcom_mss_reg_res { + const char *supply; + int uV; + int uA; +}; + struct rproc_hexagon_res { const char *hexagon_mba_image; + struct qcom_mss_reg_res proxy_supply[4]; + struct qcom_mss_reg_res active_supply[2]; char **proxy_clk_names; char **active_clk_names; }; @@ -121,8 +135,10 @@ struct q6v5 { int active_clk_count; int proxy_clk_count; - struct regulator_bulk_data supply[4]; - + struct reg_info active_regs[1]; + struct reg_info proxy_regs[3]; + int active_reg_count; + int proxy_reg_count; struct completion start_done; struct completion stop_done; @@ -138,63 +154,93 @@ struct q6v5 { size_t mpss_size; }; -enum { - Q6V5_SUPPLY_CX, - Q6V5_SUPPLY_MX, - Q6V5_SUPPLY_MSS, - Q6V5_SUPPLY_PLL, -}; - -static int q6v5_regulator_init(struct q6v5 *qproc) +static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, + const struct qcom_mss_reg_res *reg_res) { - int ret; + int rc; + int i; - qproc->supply[Q6V5_SUPPLY_CX].supply = "cx"; - qproc->supply[Q6V5_SUPPLY_MX].supply = "mx"; - qproc->supply[Q6V5_SUPPLY_MSS].supply = "mss"; - qproc->supply[Q6V5_SUPPLY_PLL].supply = "pll"; + for (i = 0; reg_res[i].supply; i++) { + regs[i].reg = devm_regulator_get(dev, reg_res[i].supply); + if (IS_ERR(regs[i].reg)) { + rc = PTR_ERR(regs[i].reg); + if (rc != -EPROBE_DEFER) + dev_err(dev, "Failed to get %s\n regulator", + reg_res[i].supply); + return rc; + } - ret = devm_regulator_bulk_get(qproc->dev, - ARRAY_SIZE(qproc->supply), qproc->supply); - if (ret < 0) { - dev_err(qproc->dev, "failed to get supplies\n"); - return ret; + regs[i].uV = reg_res[i].uV; + regs[i].uA = reg_res[i].uA; } - regulator_set_load(qproc->supply[Q6V5_SUPPLY_CX].consumer, 100000); - regulator_set_load(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 100000); - regulator_set_load(qproc->supply[Q6V5_SUPPLY_PLL].consumer, 10000); + return i; +} + +static int q6v5_regulator_enable(struct q6v5 *qproc, + struct reg_info *regs, int count) +{ + int ret; + int i; + + for (i = 0; i < count; i++) { + if (regs[i].uV > 0) { + ret = regulator_set_voltage(regs[i].reg, + regs[i].uV, INT_MAX); + if (ret) { + dev_err(qproc->dev, + "Failed to request voltage for %d.\n", + i); + goto err; + } + } + + if (regs[i].uA > 0) { + ret = regulator_set_load(regs[i].reg, + regs[i].uA); + if (ret < 0) { + dev_err(qproc->dev, + "Failed to set regulator mode\n"); + goto err; + } + } + + ret = regulator_enable(regs[i].reg); + if (ret) { + dev_err(qproc->dev, "Regulator enable failed\n"); + goto err; + } + } return 0; +err: + for (; i >= 0; i--) { + if (regs[i].uV > 0) + regulator_set_voltage(regs[i].reg, 0, INT_MAX); + + if (regs[i].uA > 0) + regulator_set_load(regs[i].reg, 0); + + regulator_disable(regs[i].reg); + } + + return ret; } -static int q6v5_regulator_enable(struct q6v5 *qproc) +static void q6v5_regulator_disable(struct q6v5 *qproc, + struct reg_info *regs, int count) { - struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer; - struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer; - int ret; + int i; - /* TODO: Q6V5_SUPPLY_CX is supposed to be set to super-turbo here */ + for (i = 0; i < count; i++) { + if (regs[i].uV > 0) + regulator_set_voltage(regs[i].reg, 0, INT_MAX); - ret = regulator_set_voltage(mx, 1050000, INT_MAX); - if (ret) - return ret; + if (regs[i].uA > 0) + regulator_set_load(regs[i].reg, 0); - regulator_set_voltage(mss, 1000000, 1150000); - - return regulator_bulk_enable(ARRAY_SIZE(qproc->supply), qproc->supply); -} - -static void q6v5_regulator_disable(struct q6v5 *qproc) -{ - struct regulator *mss = qproc->supply[Q6V5_SUPPLY_MSS].consumer; - struct regulator *mx = qproc->supply[Q6V5_SUPPLY_MX].consumer; - - /* TODO: Q6V5_SUPPLY_CX corner votes should be released */ - - regulator_bulk_disable(ARRAY_SIZE(qproc->supply), qproc->supply); - regulator_set_voltage(mx, 0, INT_MAX); - regulator_set_voltage(mss, 0, 1150000); + regulator_disable(regs[i].reg); + } } static int q6v5_clk_enable(struct device *dev, @@ -517,9 +563,10 @@ static int q6v5_start(struct rproc *rproc) struct q6v5 *qproc = (struct q6v5 *)rproc->priv; int ret; - ret = q6v5_regulator_enable(qproc); + ret = q6v5_regulator_enable(qproc, qproc->proxy_regs, + qproc->proxy_reg_count); if (ret) { - dev_err(qproc->dev, "failed to enable supplies\n"); + dev_err(qproc->dev, "failed to enable proxy supplies\n"); return ret; } @@ -527,12 +574,19 @@ static int q6v5_start(struct rproc *rproc) qproc->proxy_clk_count); if (ret) { dev_err(qproc->dev, "failed to enable proxy clocks\n"); - goto disable_vdd; + goto disable_proxy_reg; + } + + ret = q6v5_regulator_enable(qproc, qproc->active_regs, + qproc->active_reg_count); + if (ret) { + dev_err(qproc->dev, "failed to enable supplies\n"); + goto disable_proxy_clk; } ret = reset_control_deassert(qproc->mss_restart); if (ret) { dev_err(qproc->dev, "failed to deassert mss restart\n"); - goto disable_proxy_clk; + goto disable_vdd; } ret = q6v5_clk_enable(qproc->dev, qproc->active_clks, @@ -577,6 +631,8 @@ static int q6v5_start(struct rproc *rproc) q6v5_clk_disable(qproc->dev, qproc->proxy_clks, qproc->proxy_clk_count); + q6v5_regulator_disable(qproc, qproc->proxy_regs, + qproc->proxy_reg_count); return 0; @@ -588,11 +644,15 @@ halt_axi_ports: qproc->active_clk_count); assert_reset: reset_control_assert(qproc->mss_restart); +disable_vdd: + q6v5_regulator_disable(qproc, qproc->active_regs, + qproc->active_reg_count); disable_proxy_clk: q6v5_clk_disable(qproc->dev, qproc->proxy_clks, qproc->proxy_clk_count); -disable_vdd: - q6v5_regulator_disable(qproc); +disable_proxy_reg: + q6v5_regulator_disable(qproc, qproc->proxy_regs, + qproc->proxy_reg_count); return ret; } @@ -621,7 +681,8 @@ static int q6v5_stop(struct rproc *rproc) reset_control_assert(qproc->mss_restart); q6v5_clk_disable(qproc->dev, qproc->active_clks, qproc->active_clk_count); - q6v5_regulator_disable(qproc); + q6v5_regulator_disable(qproc, qproc->active_regs, + qproc->active_reg_count); return 0; } @@ -894,9 +955,21 @@ static int q6v5_probe(struct platform_device *pdev) } qproc->active_clk_count = ret; - ret = q6v5_regulator_init(qproc); - if (ret) + ret = q6v5_regulator_init(&pdev->dev, qproc->proxy_regs, + desc->proxy_supply); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get proxy regulators.\n"); goto free_rproc; + } + qproc->proxy_reg_count = ret; + + ret = q6v5_regulator_init(&pdev->dev, qproc->active_regs, + desc->active_supply); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get active regulators.\n"); + goto free_rproc; + } + qproc->active_reg_count = ret; ret = q6v5_init_reset(qproc); if (ret) @@ -948,6 +1021,29 @@ static int q6v5_remove(struct platform_device *pdev) static const struct rproc_hexagon_res msm8916_mss = { .hexagon_mba_image = "mba.mbn", + .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "mx", + .uV = 1050000, + }, + { + .supply = "cx", + .uA = 100000, + }, + { + .supply = "pll", + .uA = 100000, + }, + {} + }, + .active_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "mss", + .uV = 1050000, + .uA = 100000, + }, + {} + }, .proxy_clk_names = (char*[]){ "xo", NULL @@ -962,6 +1058,29 @@ static const struct rproc_hexagon_res msm8916_mss = { static const struct rproc_hexagon_res msm8974_mss = { .hexagon_mba_image = "mba.b00", + .proxy_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "mx", + .uV = 1050000, + }, + { + .supply = "cx", + .uA = 100000, + }, + { + .supply = "pll", + .uA = 100000, + }, + {} + }, + .active_supply = (struct qcom_mss_reg_res[]) { + { + .supply = "mss", + .uV = 1050000, + .uA = 100000, + }, + {} + }, .proxy_clk_names = (char*[]){ "xo", NULL From c008fad264f61efc809bd067becc6d1db9bb3730 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 1 Jan 2017 16:13:37 +0530 Subject: [PATCH 05/27] drivers: remoteproc: constify rproc_ops structures Declare rproc_ops structures as const as they are only passed as an argument to the function rproc_alloc. This argument is of type const, so rproc_ops structures having this property can be declared const too. Done using Coccinelle: @r1 disable optional_qualifier @ identifier i; position p; @@ static struct rproc_ops i@p = {...}; @ok1@ identifier r1.i; position p; @@ rproc_alloc(...,&i@p,...) @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct rproc_ops i; File size details: Size of the file remoteproc/da8xx_remoteproc.o remains the same before and after applying the changes. text data bss dec hex filename 1312 100 4 1416 588 remoteproc/da8xx_remoteproc.o 1312 100 4 1416 588 remoteproc/da8xx_remoteproc.o 970 240 0 1210 4ba remoteproc/omap_remoteproc.o 1002 192 0 1194 4aa remoteproc/omap_remoteproc.o 1901 240 0 2141 85d remoteproc/st_remoteproc.o 1933 192 0 2125 84d remoteproc/st_remoteproc.o 1288 96 0 1384 568 remoteproc/st_slim_rproc.o 1320 64 0 1384 568 remoteproc/st_slim_rproc.o 2121 240 0 2361 939 remoteproc/wkup_m3_rproc.o 2161 192 0 2353 931 remoteproc/wkup_m3_rproc.o Signed-off-by: Bhumika Goyal Signed-off-by: Bjorn Andersson --- drivers/remoteproc/da8xx_remoteproc.c | 2 +- drivers/remoteproc/omap_remoteproc.c | 2 +- drivers/remoteproc/st_remoteproc.c | 2 +- drivers/remoteproc/st_slim_rproc.c | 2 +- drivers/remoteproc/wkup_m3_rproc.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 1afac8f31be0..3814de28599c 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -151,7 +151,7 @@ static void da8xx_rproc_kick(struct rproc *rproc, int vqid) writel(SYSCFG_CHIPSIG2, drproc->chipsig); } -static struct rproc_ops da8xx_rproc_ops = { +static const struct rproc_ops da8xx_rproc_ops = { .start = da8xx_rproc_start, .stop = da8xx_rproc_stop, .kick = da8xx_rproc_kick, diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index fa63bf2eb885..a96ce9083f7f 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -177,7 +177,7 @@ static int omap_rproc_stop(struct rproc *rproc) return 0; } -static struct rproc_ops omap_rproc_ops = { +static const struct rproc_ops omap_rproc_ops = { .start = omap_rproc_start, .stop = omap_rproc_stop, .kick = omap_rproc_kick, diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index da4e152e9733..f21787b602e3 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -107,7 +107,7 @@ static int st_rproc_stop(struct rproc *rproc) return sw_err ?: pwr_err; } -static struct rproc_ops st_rproc_ops = { +static const struct rproc_ops st_rproc_ops = { .start = st_rproc_start, .stop = st_rproc_stop, }; diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c index 507716c8721f..6cfd862f945b 100644 --- a/drivers/remoteproc/st_slim_rproc.c +++ b/drivers/remoteproc/st_slim_rproc.c @@ -200,7 +200,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len) return va; } -static struct rproc_ops slim_rproc_ops = { +static const struct rproc_ops slim_rproc_ops = { .start = slim_rproc_start, .stop = slim_rproc_stop, .da_to_va = slim_rproc_da_to_va, diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 18175d0331fd..1ada0e51fef6 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -111,7 +111,7 @@ static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len) return va; } -static struct rproc_ops wkup_m3_rproc_ops = { +static const struct rproc_ops wkup_m3_rproc_ops = { .start = wkup_m3_rproc_start, .stop = wkup_m3_rproc_stop, .da_to_va = wkup_m3_rproc_da_to_va, From c7715e47bf6dc4c52297cde7b7aedc4530937dc5 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Mon, 30 Jan 2017 20:33:06 +0530 Subject: [PATCH 06/27] remoteproc: qcom: Compatible string based resource initialization. This patch initialize certain driver related data based on compatible string. This enable driver to handle more than one similar device in by differentiating in probe their private data. Signed-off-by: Avaneesh Kumar Dwivedi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_adsp_pil.c | 47 +++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index 43a4ed2f346c..1a07d8e05615 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -32,9 +32,11 @@ #include "qcom_mdt_loader.h" #include "remoteproc_internal.h" -#define ADSP_CRASH_REASON_SMEM 423 -#define ADSP_FIRMWARE_NAME "adsp.mdt" -#define ADSP_PAS_ID 1 +struct adsp_data { + int crash_reason_smem; + const char *firmware_name; + int pas_id; +}; struct qcom_adsp { struct device *dev; @@ -53,6 +55,9 @@ struct qcom_adsp { struct regulator *cx_supply; + int pas_id; + int crash_reason_smem; + struct completion start_done; struct completion stop_done; @@ -70,7 +75,7 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) bool relocate; int ret; - ret = qcom_scm_pas_init_image(ADSP_PAS_ID, fw->data, fw->size); + ret = qcom_scm_pas_init_image(adsp->pas_id, fw->data, fw->size); if (ret) { dev_err(&rproc->dev, "invalid firmware metadata\n"); return ret; @@ -85,7 +90,8 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) if (relocate) { adsp->mem_reloc = fw_addr; - ret = qcom_scm_pas_mem_setup(ADSP_PAS_ID, adsp->mem_phys, fw_size); + ret = qcom_scm_pas_mem_setup(adsp->pas_id, + adsp->mem_phys, fw_size); if (ret) { dev_err(&rproc->dev, "unable to setup memory for image\n"); return ret; @@ -113,7 +119,7 @@ static int adsp_start(struct rproc *rproc) if (ret) goto disable_clocks; - ret = qcom_scm_pas_auth_and_reset(ADSP_PAS_ID); + ret = qcom_scm_pas_auth_and_reset(adsp->pas_id); if (ret) { dev_err(adsp->dev, "failed to authenticate image and release reset\n"); @@ -124,7 +130,7 @@ static int adsp_start(struct rproc *rproc) msecs_to_jiffies(5000)); if (!ret) { dev_err(adsp->dev, "start timed out\n"); - qcom_scm_pas_shutdown(ADSP_PAS_ID); + qcom_scm_pas_shutdown(adsp->pas_id); ret = -ETIMEDOUT; goto disable_regulators; } @@ -157,7 +163,7 @@ static int adsp_stop(struct rproc *rproc) BIT(adsp->stop_bit), 0); - ret = qcom_scm_pas_shutdown(ADSP_PAS_ID); + ret = qcom_scm_pas_shutdown(adsp->pas_id); if (ret) dev_err(adsp->dev, "failed to shutdown: %d\n", ret); @@ -197,7 +203,7 @@ static irqreturn_t adsp_fatal_interrupt(int irq, void *dev) size_t len; char *msg; - msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, ADSP_CRASH_REASON_SMEM, &len); + msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, adsp->crash_reason_smem, &len); if (!IS_ERR(msg) && len > 0 && msg[0]) dev_err(adsp->dev, "fatal error received: %s\n", msg); @@ -311,20 +317,25 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) static int adsp_probe(struct platform_device *pdev) { + const struct adsp_data *desc; struct qcom_adsp *adsp; struct rproc *rproc; int ret; + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + if (!qcom_scm_is_available()) return -EPROBE_DEFER; - if (!qcom_scm_pas_supported(ADSP_PAS_ID)) { - dev_err(&pdev->dev, "PAS is not available for ADSP\n"); + if (!qcom_scm_pas_supported(desc->pas_id)) { + dev_err(&pdev->dev, "PAS is not available for subsystem\n"); return -ENXIO; } rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops, - ADSP_FIRMWARE_NAME, sizeof(*adsp)); + desc->firmware_name, sizeof(*adsp)); if (!rproc) { dev_err(&pdev->dev, "unable to allocate remoteproc\n"); return -ENOMEM; @@ -335,6 +346,8 @@ static int adsp_probe(struct platform_device *pdev) adsp = (struct qcom_adsp *)rproc->priv; adsp->dev = &pdev->dev; adsp->rproc = rproc; + adsp->pas_id = desc->pas_id; + adsp->crash_reason_smem = desc->crash_reason_smem; platform_set_drvdata(pdev, adsp); init_completion(&adsp->start_done); @@ -407,9 +420,15 @@ static int adsp_remove(struct platform_device *pdev) return 0; } +static const struct adsp_data adsp_resource_init = { + .crash_reason_smem = 423, + .firmware_name = "adsp.mdt", + .pas_id = 1, +}; + static const struct of_device_id adsp_of_match[] = { - { .compatible = "qcom,msm8974-adsp-pil" }, - { .compatible = "qcom,msm8996-adsp-pil" }, + { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, + { .compatible = "qcom,msm8996-adsp-pil", .data = &adsp_resource_init}, { }, }; MODULE_DEVICE_TABLE(of, adsp_of_match); From e323fc030c458d2f3eb1b9031cb4334ebf9a3484 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Mon, 30 Jan 2017 20:33:07 +0530 Subject: [PATCH 07/27] remoteproc: qcom: Add additional agree2_clk and px regulator resource. This patch add additional clock and regulator resource which are initialized based on compatible and has no impact on existing driver working. This resourse addition enable the existing driver to handle. low pass sensor processor device also. Signed-off-by: Avaneesh Kumar Dwivedi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_adsp_pil.c | 43 ++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index 1a07d8e05615..87f8d4069500 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -36,6 +36,7 @@ struct adsp_data { int crash_reason_smem; const char *firmware_name; int pas_id; + bool has_aggre2_clk; }; struct qcom_adsp { @@ -52,11 +53,14 @@ struct qcom_adsp { unsigned stop_bit; struct clk *xo; + struct clk *aggre2_clk; struct regulator *cx_supply; + struct regulator *px_supply; int pas_id; int crash_reason_smem; + bool has_aggre2_clk; struct completion start_done; struct completion stop_done; @@ -115,15 +119,23 @@ static int adsp_start(struct rproc *rproc) if (ret) return ret; + ret = clk_prepare_enable(adsp->aggre2_clk); + if (ret) + goto disable_xo_clk; + ret = regulator_enable(adsp->cx_supply); if (ret) - goto disable_clocks; + goto disable_aggre2_clk; + + ret = regulator_enable(adsp->px_supply); + if (ret) + goto disable_cx_supply; ret = qcom_scm_pas_auth_and_reset(adsp->pas_id); if (ret) { dev_err(adsp->dev, "failed to authenticate image and release reset\n"); - goto disable_regulators; + goto disable_px_supply; } ret = wait_for_completion_timeout(&adsp->start_done, @@ -132,14 +144,18 @@ static int adsp_start(struct rproc *rproc) dev_err(adsp->dev, "start timed out\n"); qcom_scm_pas_shutdown(adsp->pas_id); ret = -ETIMEDOUT; - goto disable_regulators; + goto disable_px_supply; } ret = 0; -disable_regulators: +disable_px_supply: + regulator_disable(adsp->px_supply); +disable_cx_supply: regulator_disable(adsp->cx_supply); -disable_clocks: +disable_aggre2_clk: + clk_disable_unprepare(adsp->aggre2_clk); +disable_xo_clk: clk_disable_unprepare(adsp->xo); return ret; @@ -250,6 +266,17 @@ static int adsp_init_clock(struct qcom_adsp *adsp) return ret; } + if (adsp->has_aggre2_clk) { + adsp->aggre2_clk = devm_clk_get(adsp->dev, "aggre2"); + if (IS_ERR(adsp->aggre2_clk)) { + ret = PTR_ERR(adsp->aggre2_clk); + if (ret != -EPROBE_DEFER) + dev_err(adsp->dev, + "failed to get aggre2 clock"); + return ret; + } + } + return 0; } @@ -261,6 +288,10 @@ static int adsp_init_regulator(struct qcom_adsp *adsp) regulator_set_load(adsp->cx_supply, 100000); + adsp->px_supply = devm_regulator_get(adsp->dev, "px"); + if (IS_ERR(adsp->px_supply)) + return PTR_ERR(adsp->px_supply); + return 0; } @@ -348,6 +379,7 @@ static int adsp_probe(struct platform_device *pdev) adsp->rproc = rproc; adsp->pas_id = desc->pas_id; adsp->crash_reason_smem = desc->crash_reason_smem; + adsp->has_aggre2_clk = desc->has_aggre2_clk; platform_set_drvdata(pdev, adsp); init_completion(&adsp->start_done); @@ -424,6 +456,7 @@ static const struct adsp_data adsp_resource_init = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, + .has_aggre2_clk = false, }; static const struct of_device_id adsp_of_match[] = { From 90a068ed3fc93e088d8a216826e33b0c14edec59 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Mon, 30 Jan 2017 20:33:08 +0530 Subject: [PATCH 08/27] remoteproc: qcom: Add SLPI rproc support to load and boot slpi proc. This patch add slpi remoteproc support in existing adsp rproc driver. Signed-off-by: Avaneesh Kumar Dwivedi [bjorn: documented aggre2 and px-supply] Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,adsp.txt | 41 +++++++++++++++++-- drivers/remoteproc/qcom_adsp_pil.c | 10 ++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt index b85885a298d8..75ad7b8df0b1 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt @@ -9,6 +9,7 @@ on the Qualcomm ADSP Hexagon core. Definition: must be one of: "qcom,msm8974-adsp-pil" "qcom,msm8996-adsp-pil" + "qcom,msm8996-slpi-pil" - interrupts-extended: Usage: required @@ -24,13 +25,13 @@ on the Qualcomm ADSP Hexagon core. - clocks: Usage: required Value type: - Definition: reference to the xo clock to be held on behalf of the - booting Hexagon core + Definition: reference to the xo clock and optionally aggre2 clock to be + held on behalf of the booting Hexagon core - clock-names: Usage: required Value type: - Definition: must be "xo" + Definition: must be "xo" and optionally include "aggre2" - cx-supply: Usage: required @@ -38,6 +39,12 @@ on the Qualcomm ADSP Hexagon core. Definition: reference to the regulator to be held on behalf of the booting Hexagon core +- px-supply: + Usage: required + Value type: + Definition: reference to the px regulator to be held on behalf of the + booting Hexagon core + - memory-region: Usage: required Value type: @@ -96,3 +103,31 @@ ADSP, as it is found on MSM8974 boards. qcom,smd-edge = <1>; }; }; + +The following example describes the resources needed to boot control the +SLPI, as it is found on MSM8996 boards. + + slpi { + compatible = "qcom,msm8996-slpi-pil"; + interrupts-extended = <&intc 0 390 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmcc MSM8996_RPM_SMD_XO_CLK_SRC>, + <&rpmcc MSM8996_RPM_SMD_AGGR2_NOC_CLK>; + clock-names = "xo", "aggre2"; + + cx-supply = <&pm8994_l26>; + px-supply = <&pm8994_lvs2>; + + memory-region = <&slpi_region>; + qcom,smem-states = <&slpi_smp2p_out 0>; + qcom,smem-state-names = "stop"; + }; diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index 87f8d4069500..a65351ea1889 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -1,5 +1,5 @@ /* - * Qualcomm ADSP Peripheral Image Loader for MSM8974 and MSM8996 + * Qualcomm ADSP/SLPI Peripheral Image Loader for MSM8974 and MSM8996 * * Copyright (C) 2016 Linaro Ltd * Copyright (C) 2014 Sony Mobile Communications AB @@ -459,9 +459,17 @@ static const struct adsp_data adsp_resource_init = { .has_aggre2_clk = false, }; +static const struct adsp_data slpi_resource_init = { + .crash_reason_smem = 424, + .firmware_name = "slpi.mdt", + .pas_id = 12, + .has_aggre2_clk = true, +}; + static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, { .compatible = "qcom,msm8996-adsp-pil", .data = &adsp_resource_init}, + { .compatible = "qcom,msm8996-slpi-pil", .data = &slpi_resource_init}, { }, }; MODULE_DEVICE_TABLE(of, adsp_of_match); From b003d45b37b2d2c682f279e6fd5a9254b8ddc244 Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Mon, 23 Jan 2017 17:48:48 -0800 Subject: [PATCH 09/27] remoteproc: Move rproc_delete_debug_dir() to rproc_del() The "remoteproc{0,1...}" sysfs entries are added in rproc_add() and deleted in rproc_type_release() instead of in rproc_del(). That leaves these lingering entries sticking around after we return from rproc_del(). Move the rproc_delete_debug_dir() to rproc_del() to fix this. Signed-off-by: Sarangdhar Joshi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 90b05c72186c..44f119a671fe 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1315,8 +1315,6 @@ static void rproc_type_release(struct device *dev) dev_info(&rproc->dev, "releasing %s\n", rproc->name); - rproc_delete_debug_dir(rproc); - idr_destroy(&rproc->notifyids); if (rproc->index >= 0) @@ -1491,6 +1489,8 @@ int rproc_del(struct rproc *rproc) if (rproc->auto_boot) rproc_shutdown(rproc); + rproc_delete_debug_dir(rproc); + /* the rproc is downref'ed as soon as it's removed from the klist */ mutex_lock(&rproc_list_mutex); list_del(&rproc->node); From 608d792192d7136d354bc1b44585c441164dc54e Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Mon, 23 Jan 2017 17:53:18 -0800 Subject: [PATCH 10/27] remoteproc: Add RPROC_DELETED state Add new state RPROC_DELETED to handle synchronization between rproc_del() and other operations on rproc. This state represents the rproc device that has been "deleted". CC: Loic Pallardy CC: Bjorn Andersson Signed-off-by: Sarangdhar Joshi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_sysfs.c | 1 + include/linux/remoteproc.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index bc5b0e00efb1..47be411400e5 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -73,6 +73,7 @@ static const char * const rproc_state_string[] = { [RPROC_SUSPENDED] = "suspended", [RPROC_RUNNING] = "running", [RPROC_CRASHED] = "crashed", + [RPROC_DELETED] = "deleted", [RPROC_LAST] = "invalid", }; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 8265d351c9f0..e691f64fc7be 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -346,6 +346,7 @@ struct rproc_ops { * a message. * @RPROC_RUNNING: device is up and running * @RPROC_CRASHED: device has crashed; need to start recovery + * @RPROC_DELETED: device is deleted * @RPROC_LAST: just keep this one at the end * * Please note that the values of these states are used as indices @@ -359,7 +360,8 @@ enum rproc_state { RPROC_SUSPENDED = 1, RPROC_RUNNING = 2, RPROC_CRASHED = 3, - RPROC_LAST = 4, + RPROC_DELETED = 4, + RPROC_LAST = 5, }; /** From 2099c77d4af7d1582db6d4437014cf18fe62e74b Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Mon, 23 Jan 2017 17:53:19 -0800 Subject: [PATCH 11/27] remoteproc: Drop firmware_loading_complete firmware_loading_complete is used to synchronize operations on rproc while asynchronous firmware loading is in progress. However, rproc_boot() no longer waits on firmware_loading_complete. Hence drop this completion variable altogether and handle the race between rproc_del() and rproc_boot() using new state RPROC_DELETED. The request_firmware_nowait() will hold the reference to rproc device by using a get_device()/put_device(), so the rproc struct will remain valid even when we return from rproc_del() before the asynchronous call to rproc_fw_config_virtio() completes. CC: Loic Pallardy CC: Bjorn Andersson Signed-off-by: Sarangdhar Joshi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 22 +++++++++++----------- include/linux/remoteproc.h | 2 -- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 44f119a671fe..a7ee05006cca 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -977,17 +977,12 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) rproc_boot(rproc); release_firmware(fw); - /* allow rproc_del() contexts, if any, to proceed */ - complete_all(&rproc->firmware_loading_complete); } static int rproc_add_virtio_devices(struct rproc *rproc) { int ret; - /* rproc_del() calls must wait until async loader completes */ - init_completion(&rproc->firmware_loading_complete); - /* * We must retrieve early virtio configuration info from * the firmware (e.g. whether to register a virtio device, @@ -999,10 +994,8 @@ static int rproc_add_virtio_devices(struct rproc *rproc) ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, rproc->firmware, &rproc->dev, GFP_KERNEL, rproc, rproc_fw_config_virtio); - if (ret < 0) { + if (ret < 0) dev_err(&rproc->dev, "request_firmware_nowait err: %d\n", ret); - complete_all(&rproc->firmware_loading_complete); - } return ret; } @@ -1099,6 +1092,12 @@ static int __rproc_boot(struct rproc *rproc) return ret; } + if (rproc->state == RPROC_DELETED) { + ret = -ENODEV; + dev_err(dev, "can't boot deleted rproc %s\n", rproc->name); + goto unlock_mutex; + } + /* skip the boot process if rproc is already powered up */ if (atomic_inc_return(&rproc->power) > 1) { ret = 0; @@ -1481,14 +1480,15 @@ int rproc_del(struct rproc *rproc) if (!rproc) return -EINVAL; - /* if rproc is just being registered, wait */ - wait_for_completion(&rproc->firmware_loading_complete); - /* if rproc is marked always-on, rproc_add() booted it */ /* TODO: make sure this works with rproc->power > 1 */ if (rproc->auto_boot) rproc_shutdown(rproc); + mutex_lock(&rproc->lock); + rproc->state = RPROC_DELETED; + mutex_unlock(&rproc->lock); + rproc_delete_debug_dir(rproc); /* the rproc is downref'ed as soon as it's removed from the klist */ diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index e691f64fc7be..81da49564ff4 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -399,7 +399,6 @@ enum rproc_crash_type { * @num_traces: number of trace buffers * @carveouts: list of physically contiguous memory allocations * @mappings: list of iommu mappings we initiated, needed on shutdown - * @firmware_loading_complete: marks e/o asynchronous firmware loading * @bootaddr: address of first instruction to boot rproc with (optional) * @rvdevs: list of remote virtio devices * @subdevs: list of subdevices, to following the running state @@ -431,7 +430,6 @@ struct rproc { int num_traces; struct list_head carveouts; struct list_head mappings; - struct completion firmware_loading_complete; u32 bootaddr; struct list_head rvdevs; struct list_head subdevs; From ec671b5360b914fb3ad79053593d195996a95dde Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 1 Feb 2017 17:56:28 +0100 Subject: [PATCH 12/27] remoteproc: qcom: fix initializers for qcom_mss_reg_res array The recently added initialization is rather unusual because it uses a constructor for a variable-length array to assign a constant structure to a member that uses a fixed-length array. This confuses clang and breaks the build. drivers/remoteproc/qcom_q6v5_pil.c:1024:18: error: incompatible pointer types initializing 'const char *' with an expression of type :%s 'struct qcom_mss_reg_res [4]' [-Werror,-Wincompatible-pointer-types] .proxy_supply = (struct qcom_mss_reg_res[]) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/remoteproc/qcom_q6v5_pil.c:1024:18: warning: suggest braces around initialization of subobject [-Wmissing-braces] .proxy_supply = (struct qcom_mss_reg_res[]) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We can either turn this constructor into a regular initializer by removing the 'struct qcom_mss_reg_res[])', or we can make the array variable length. The latter approach is used for the arrays of strings in the same structure, so let's use that here too. Fixes: 19f902b53b47 ("remoteproc: qcom: Initialize and enable proxy and active regulators.") Signed-off-by: Arnd Bergmann Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 9a5149573298..8d60ad2a2851 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -107,8 +107,8 @@ struct qcom_mss_reg_res { struct rproc_hexagon_res { const char *hexagon_mba_image; - struct qcom_mss_reg_res proxy_supply[4]; - struct qcom_mss_reg_res active_supply[2]; + struct qcom_mss_reg_res *proxy_supply; + struct qcom_mss_reg_res *active_supply; char **proxy_clk_names; char **active_clk_names; }; From 2bb5d9069999a2c2195a05f4aa3da7f14ea3102d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 30 Jan 2017 03:20:27 -0800 Subject: [PATCH 13/27] remoteproc: qcom: q6v5: Remove mss supply from 8916 The Q6V5 in MSM8916 doesn't have a mss supply, so remove this and update the code to support cases without proxy or active supplies. Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pil.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 8d60ad2a2851..b9ce66e28f8b 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -160,6 +160,9 @@ static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, int rc; int i; + if (!reg_res) + return 0; + for (i = 0; reg_res[i].supply; i++) { regs[i].reg = devm_regulator_get(dev, reg_res[i].supply); if (IS_ERR(regs[i].reg)) { @@ -1036,14 +1039,6 @@ static const struct rproc_hexagon_res msm8916_mss = { }, {} }, - .active_supply = (struct qcom_mss_reg_res[]) { - { - .supply = "mss", - .uV = 1050000, - .uA = 100000, - }, - {} - }, .proxy_clk_names = (char*[]){ "xo", NULL From e7fd25226295270cc248254e7406d1e19181aea9 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 26 Jan 2017 13:58:35 -0800 Subject: [PATCH 14/27] remoteproc: qcom: q6v5: Decouple driver from MDT loader Rather than duplicating half of the MDT loader in the validation step move the entire MDT parser into the q6v5 driver. This allows us to make the shared MDT-loader call the SCM PAS operations directly which simplifies the client code and allows for better reuse of the code. Cc: Avaneesh Kumar Dwivedi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 1 - drivers/remoteproc/qcom_q6v5_pil.c | 146 ++++++++++++++++++----------- 2 files changed, 90 insertions(+), 57 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index a5e888043f1f..454fd9a4dd96 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -92,7 +92,6 @@ config QCOM_Q6V5_PIL depends on QCOM_SMEM depends on REMOTEPROC select MFD_SYSCON - select QCOM_MDT_LOADER select QCOM_SCM help Say y here to support the Qualcomm Peripherial Image Loader for the diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index b9ce66e28f8b..83a78daf55ef 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -37,8 +37,6 @@ #include -#define MPSS_FIRMWARE_NAME "modem.mdt" - #define MPSS_CRASH_REASON_SMEM 421 /* RMB Status Register Values */ @@ -277,6 +275,16 @@ static void q6v5_clk_disable(struct device *dev, clk_disable_unprepare(clks[i]); } +static struct resource_table *q6v5_find_rsc_table(struct rproc *rproc, + const struct firmware *fw, + int *tablesz) +{ + static struct resource_table table = { .ver = 1, }; + + *tablesz = sizeof(table); + return &table; +} + static int q6v5_load(struct rproc *rproc, const struct firmware *fw) { struct q6v5 *qproc = rproc->priv; @@ -287,7 +295,7 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw) } static const struct rproc_fw_ops q6v5_fw_ops = { - .find_rsc_table = qcom_mdt_find_rsc_table, + .find_rsc_table = q6v5_find_rsc_table, .load = q6v5_load, }; @@ -464,45 +472,109 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) return ret < 0 ? ret : 0; } -static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw) +static bool q6v5_phdr_valid(const struct elf32_phdr *phdr) +{ + if (phdr->p_type != PT_LOAD) + return false; + + if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) + return false; + + if (!phdr->p_memsz) + return false; + + return true; +} + +static int q6v5_mpss_load(struct q6v5 *qproc) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; + const struct firmware *seg_fw; + const struct firmware *fw; struct elf32_hdr *ehdr; + phys_addr_t mpss_reloc; phys_addr_t boot_addr; - phys_addr_t fw_addr; - bool relocate; + phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; + phys_addr_t max_addr = 0; + bool relocate = false; + char seg_name[10]; + size_t offset; size_t size; + void *ptr; int ret; int i; - ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate); - if (ret) { - dev_err(qproc->dev, "failed to parse mdt header\n"); + ret = request_firmware(&fw, "modem.mdt", qproc->dev); + if (ret < 0) { + dev_err(qproc->dev, "unable to load modem.mdt\n"); return ret; } - if (relocate) - boot_addr = qproc->mpss_phys; - else - boot_addr = fw_addr; + /* Initialize the RMB validator */ + writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); + + ret = q6v5_mpss_init_image(qproc, fw); + if (ret) + goto release_firmware; ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); - for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + + for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; - if (phdr->p_type != PT_LOAD) + if (!q6v5_phdr_valid(phdr)) continue; - if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) + if (phdr->p_flags & QCOM_MDT_RELOCATABLE) + relocate = true; + + if (phdr->p_paddr < min_addr) + min_addr = phdr->p_paddr; + + if (phdr->p_paddr + phdr->p_memsz > max_addr) + max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); + } + + mpss_reloc = relocate ? min_addr : qproc->mpss_phys; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &phdrs[i]; + + if (!q6v5_phdr_valid(phdr)) continue; - if (!phdr->p_memsz) - continue; + offset = phdr->p_paddr - mpss_reloc; + if (offset < 0 || offset + phdr->p_memsz > qproc->mpss_size) { + dev_err(qproc->dev, "segment outside memory range\n"); + ret = -EINVAL; + goto release_firmware; + } + + ptr = qproc->mpss_region + offset; + + if (phdr->p_filesz) { + snprintf(seg_name, sizeof(seg_name), "modem.b%02d", i); + ret = request_firmware(&seg_fw, seg_name, qproc->dev); + if (ret) { + dev_err(qproc->dev, "failed to load %s\n", seg_name); + goto release_firmware; + } + + memcpy(ptr, seg_fw->data, seg_fw->size); + + release_firmware(seg_fw); + } + + if (phdr->p_memsz > phdr->p_filesz) { + memset(ptr + phdr->p_filesz, 0, + phdr->p_memsz - phdr->p_filesz); + } size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); if (!size) { + boot_addr = relocate ? qproc->mpss_phys : min_addr; writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG); writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); } @@ -517,44 +589,6 @@ static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw) else if (ret < 0) dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret); - return ret < 0 ? ret : 0; -} - -static int q6v5_mpss_load(struct q6v5 *qproc) -{ - const struct firmware *fw; - phys_addr_t fw_addr; - bool relocate; - int ret; - - ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev); - if (ret < 0) { - dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n"); - return ret; - } - - ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate); - if (ret) { - dev_err(qproc->dev, "failed to parse mdt header\n"); - goto release_firmware; - } - - if (relocate) - qproc->mpss_reloc = fw_addr; - - /* Initialize the RMB validator */ - writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); - - ret = q6v5_mpss_init_image(qproc, fw); - if (ret) - goto release_firmware; - - ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME); - if (ret) - goto release_firmware; - - ret = q6v5_mpss_validate(qproc, fw); - release_firmware: release_firmware(fw); From bde440eee27021617fcd33000209925cdc67db12 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 27 Jan 2017 02:28:32 -0800 Subject: [PATCH 15/27] remoteproc: qcom: Extract non-mdt related helper In preparation for moving the mdt loader out of remoteproc let's move the somewhat unrelated resource table dummy helper to a Qualcomm "common" file. Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 6 ++++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_adsp_pil.c | 1 + drivers/remoteproc/qcom_common.c | 46 ++++++++++++++++++++++++++++ drivers/remoteproc/qcom_common.h | 11 +++++++ drivers/remoteproc/qcom_mdt_loader.c | 19 ------------ drivers/remoteproc/qcom_mdt_loader.h | 1 - drivers/remoteproc/qcom_q6v5_pil.c | 1 + drivers/remoteproc/qcom_wcnss.c | 1 + 9 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 drivers/remoteproc/qcom_common.c create mode 100644 drivers/remoteproc/qcom_common.h diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 454fd9a4dd96..71ea703190c6 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -78,11 +78,15 @@ config QCOM_ADSP_PIL depends on QCOM_SMEM select MFD_SYSCON select QCOM_MDT_LOADER + select QCOM_RPROC_COMMON select QCOM_SCM help Say y here to support the TrustZone based Peripherial Image Loader for the Qualcomm ADSP remote processors. +config QCOM_RPROC_COMMON + tristate + config QCOM_MDT_LOADER tristate @@ -92,6 +96,7 @@ config QCOM_Q6V5_PIL depends on QCOM_SMEM depends on REMOTEPROC select MFD_SYSCON + select QCOM_RPROC_COMMON select QCOM_SCM help Say y here to support the Qualcomm Peripherial Image Loader for the @@ -104,6 +109,7 @@ config QCOM_WCNSS_PIL depends on QCOM_SMEM depends on REMOTEPROC select QCOM_MDT_LOADER + select QCOM_RPROC_COMMON select QCOM_SCM help Say y here to support the Peripheral Image Loader for the Qualcomm diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 0938ea3c41ba..d4f9525a226d 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o obj-$(CONFIG_QCOM_MDT_LOADER) += qcom_mdt_loader.o +obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o qcom_wcnss_pil-y += qcom_wcnss.o diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index a65351ea1889..4fb4c4b47875 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -29,6 +29,7 @@ #include #include +#include "qcom_common.h" #include "qcom_mdt_loader.h" #include "remoteproc_internal.h" diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c new file mode 100644 index 000000000000..bd400336e209 --- /dev/null +++ b/drivers/remoteproc/qcom_common.c @@ -0,0 +1,46 @@ +/* + * Qualcomm Peripheral Image Loader helpers + * + * Copyright (C) 2016 Linaro Ltd + * Copyright (C) 2015 Sony Mobile Communications Inc + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "remoteproc_internal.h" +#include "qcom_common.h" + +/** + * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc + * @rproc: remoteproc handle + * @fw: firmware header + * @tablesz: outgoing size of the table + * + * Returns a dummy table. + */ +struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc, + const struct firmware *fw, + int *tablesz) +{ + static struct resource_table table = { .ver = 1, }; + + *tablesz = sizeof(table); + return &table; +} +EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table); + +MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h new file mode 100644 index 000000000000..caecf27c4ffa --- /dev/null +++ b/drivers/remoteproc/qcom_common.h @@ -0,0 +1,11 @@ +#ifndef __RPROC_QCOM_COMMON_H__ +#define __RPROC_QCOM_COMMON_H__ + +struct resource_table; +struct rproc; + +struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc, + const struct firmware *fw, + int *tablesz); + +#endif diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c index 2ff18cd6c096..897e14512123 100644 --- a/drivers/remoteproc/qcom_mdt_loader.c +++ b/drivers/remoteproc/qcom_mdt_loader.c @@ -26,25 +26,6 @@ #include "remoteproc_internal.h" #include "qcom_mdt_loader.h" -/** - * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc - * @rproc: remoteproc handle - * @fw: firmware header - * @tablesz: outgoing size of the table - * - * Returns a dummy table. - */ -struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc, - const struct firmware *fw, - int *tablesz) -{ - static struct resource_table table = { .ver = 1, }; - - *tablesz = sizeof(table); - return &table; -} -EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table); - /** * qcom_mdt_parse() - extract useful parameters from the mdt header * @fw: firmware handle diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/drivers/remoteproc/qcom_mdt_loader.h index c5d7122755b6..e513548e52ec 100644 --- a/drivers/remoteproc/qcom_mdt_loader.h +++ b/drivers/remoteproc/qcom_mdt_loader.h @@ -5,7 +5,6 @@ #define QCOM_MDT_TYPE_HASH (2 << 24) #define QCOM_MDT_RELOCATABLE BIT(27) -struct resource_table * qcom_mdt_find_rsc_table(struct rproc *rproc, const struct firmware *fw, int *tablesz); int qcom_mdt_load(struct rproc *rproc, const struct firmware *fw, const char *fw_name); int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate); diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 83a78daf55ef..2e44c06e604a 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -33,6 +33,7 @@ #include #include "remoteproc_internal.h" +#include "qcom_common.h" #include "qcom_mdt_loader.h" #include diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index ebd61f5d18bb..f158f8243b04 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -32,6 +32,7 @@ #include #include +#include "qcom_common.h" #include "qcom_mdt_loader.h" #include "remoteproc_internal.h" #include "qcom_wcnss.h" From 3e8b571a9a0881ba3381ca0915995696da145ab8 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 27 Jan 2017 02:06:36 -0800 Subject: [PATCH 16/27] remoteproc: qcom: mdt_loader: Don't overwrite firmware object The "fw" firmware object is passed from the remoteproc core and should not be overwritten, as that results in leaked buffers and a double free of the the last firmware object. Fixes: 051fb70fd4ea ("remoteproc: qcom: Driver for the self-authenticating Hexagon v5") Cc: stable@vger.kernel.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_mdt_loader.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c index 897e14512123..fe7d5207ad17 100644 --- a/drivers/remoteproc/qcom_mdt_loader.c +++ b/drivers/remoteproc/qcom_mdt_loader.c @@ -97,6 +97,7 @@ int qcom_mdt_load(struct rproc *rproc, const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; const struct elf32_hdr *ehdr; + const struct firmware *seg_fw; size_t fw_name_len; char *fw_name; void *ptr; @@ -135,16 +136,16 @@ int qcom_mdt_load(struct rproc *rproc, if (phdr->p_filesz) { sprintf(fw_name + fw_name_len - 3, "b%02d", i); - ret = request_firmware(&fw, fw_name, &rproc->dev); + ret = request_firmware(&seg_fw, fw_name, &rproc->dev); if (ret) { dev_err(&rproc->dev, "failed to load %s\n", fw_name); break; } - memcpy(ptr, fw->data, fw->size); + memcpy(ptr, seg_fw->data, seg_fw->size); - release_firmware(fw); + release_firmware(seg_fw); } if (phdr->p_memsz > phdr->p_filesz) From 7f0dd07a9b29cfadffcd2fa08902a844f5c94e86 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 27 Jan 2017 02:17:23 -0800 Subject: [PATCH 17/27] remoteproc: qcom: mdt_loader: Refactor MDT loader Pushing the SCM calls into the MDT loader reduces duplication in the callers and allows for non-remoteproc clients to use the helper for parsing and loading MDT files. Cc: Andy Gross Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_adsp_pil.c | 30 +----- drivers/remoteproc/qcom_mdt_loader.c | 139 ++++++++++++++++++--------- drivers/remoteproc/qcom_mdt_loader.h | 7 +- drivers/remoteproc/qcom_wcnss.c | 29 +----- 4 files changed, 99 insertions(+), 106 deletions(-) diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index 4fb4c4b47875..c1ee5c818b42 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -75,35 +75,9 @@ struct qcom_adsp { static int adsp_load(struct rproc *rproc, const struct firmware *fw) { struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; - phys_addr_t fw_addr; - size_t fw_size; - bool relocate; - int ret; - ret = qcom_scm_pas_init_image(adsp->pas_id, fw->data, fw->size); - if (ret) { - dev_err(&rproc->dev, "invalid firmware metadata\n"); - return ret; - } - - ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate); - if (ret) { - dev_err(&rproc->dev, "failed to parse mdt header\n"); - return ret; - } - - if (relocate) { - adsp->mem_reloc = fw_addr; - - ret = qcom_scm_pas_mem_setup(adsp->pas_id, - adsp->mem_phys, fw_size); - if (ret) { - dev_err(&rproc->dev, "unable to setup memory for image\n"); - return ret; - } - } - - return qcom_mdt_load(rproc, fw, rproc->firmware); + return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id, + adsp->mem_region, adsp->mem_phys, adsp->mem_size); } static const struct rproc_fw_ops adsp_fw_ops = { diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c index fe7d5207ad17..790ab31f31ff 100644 --- a/drivers/remoteproc/qcom_mdt_loader.c +++ b/drivers/remoteproc/qcom_mdt_loader.c @@ -15,35 +15,44 @@ * GNU General Public License for more details. */ +#include #include #include #include #include -#include +#include #include #include -#include "remoteproc_internal.h" #include "qcom_mdt_loader.h" +static bool mdt_phdr_valid(const struct elf32_phdr *phdr) +{ + if (phdr->p_type != PT_LOAD) + return false; + + if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) + return false; + + if (!phdr->p_memsz) + return false; + + return true; +} + /** - * qcom_mdt_parse() - extract useful parameters from the mdt header - * @fw: firmware handle - * @fw_addr: optional reference for base of the firmware's memory region - * @fw_size: optional reference for size of the firmware's memory region - * @fw_relocate: optional reference for flagging if the firmware is relocatable + * qcom_mdt_get_size() - acquire size of the memory region needed to load mdt + * @fw: firmware object for the mdt file * - * Returns 0 on success, negative errno otherwise. + * Returns size of the loaded firmware blob, or -EINVAL on failure. */ -int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, - size_t *fw_size, bool *fw_relocate) +ssize_t qcom_mdt_get_size(const struct firmware *fw) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; const struct elf32_hdr *ehdr; phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; phys_addr_t max_addr = 0; - bool relocate = false; int i; ehdr = (struct elf32_hdr *)fw->data; @@ -52,18 +61,9 @@ int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; - if (phdr->p_type != PT_LOAD) + if (!mdt_phdr_valid(phdr)) continue; - if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) - continue; - - if (!phdr->p_memsz) - continue; - - if (phdr->p_flags & QCOM_MDT_RELOCATABLE) - relocate = true; - if (phdr->p_paddr < min_addr) min_addr = phdr->p_paddr; @@ -71,39 +71,44 @@ int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); } - if (fw_addr) - *fw_addr = min_addr; - if (fw_size) - *fw_size = max_addr - min_addr; - if (fw_relocate) - *fw_relocate = relocate; - - return 0; + return min_addr < max_addr ? max_addr - min_addr : -EINVAL; } -EXPORT_SYMBOL_GPL(qcom_mdt_parse); +EXPORT_SYMBOL_GPL(qcom_mdt_get_size); /** - * qcom_mdt_load() - load the firmware which header is defined in fw - * @rproc: rproc handle - * @fw: frimware object for the header - * @firmware: filename of the firmware, for building .bXX names + * qcom_mdt_load() - load the firmware which header is loaded as fw + * @dev: device handle to associate resources with + * @fw: firmware object for the mdt file + * @firmware: name of the firmware, for construction of segment file names + * @pas_id: PAS identifier + * @mem_region: allocated memory region to load firmware into + * @mem_phys: physical address of allocated memory region + * @mem_size: size of the allocated memory region * * Returns 0 on success, negative errno otherwise. */ -int qcom_mdt_load(struct rproc *rproc, - const struct firmware *fw, - const char *firmware) +int qcom_mdt_load(struct device *dev, const struct firmware *fw, + const char *firmware, int pas_id, void *mem_region, + phys_addr_t mem_phys, size_t mem_size) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; const struct elf32_hdr *ehdr; const struct firmware *seg_fw; + phys_addr_t mem_reloc; + phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; + phys_addr_t max_addr = 0; size_t fw_name_len; + size_t offset; char *fw_name; + bool relocate = false; void *ptr; int ret; int i; + if (!fw || !mem_region || !mem_phys || !mem_size) + return -EINVAL; + ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); @@ -115,31 +120,68 @@ int qcom_mdt_load(struct rproc *rproc, if (!fw_name) return -ENOMEM; + ret = qcom_scm_pas_init_image(pas_id, fw->data, fw->size); + if (ret) { + dev_err(dev, "invalid firmware metadata\n"); + goto out; + } + for (i = 0; i < ehdr->e_phnum; i++) { phdr = &phdrs[i]; - if (phdr->p_type != PT_LOAD) + if (!mdt_phdr_valid(phdr)) continue; - if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) + if (phdr->p_flags & QCOM_MDT_RELOCATABLE) + relocate = true; + + if (phdr->p_paddr < min_addr) + min_addr = phdr->p_paddr; + + if (phdr->p_paddr + phdr->p_memsz > max_addr) + max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); + } + + if (relocate) { + ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); + if (ret) { + dev_err(dev, "unable to setup relocation\n"); + goto out; + } + + /* + * The image is relocatable, so offset each segment based on + * the lowest segment address. + */ + mem_reloc = min_addr; + } else { + /* + * Image is not relocatable, so offset each segment based on + * the allocated physical chunk of memory. + */ + mem_reloc = mem_phys; + } + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &phdrs[i]; + + if (!mdt_phdr_valid(phdr)) continue; - if (!phdr->p_memsz) - continue; - - ptr = rproc_da_to_va(rproc, phdr->p_paddr, phdr->p_memsz); - if (!ptr) { - dev_err(&rproc->dev, "segment outside memory range\n"); + offset = phdr->p_paddr - mem_reloc; + if (offset < 0 || offset + phdr->p_memsz > mem_size) { + dev_err(dev, "segment outside memory range\n"); ret = -EINVAL; break; } + ptr = mem_region + offset; + if (phdr->p_filesz) { sprintf(fw_name + fw_name_len - 3, "b%02d", i); - ret = request_firmware(&seg_fw, fw_name, &rproc->dev); + ret = request_firmware(&seg_fw, fw_name, dev); if (ret) { - dev_err(&rproc->dev, "failed to load %s\n", - fw_name); + dev_err(dev, "failed to load %s\n", fw_name); break; } @@ -152,6 +194,7 @@ int qcom_mdt_load(struct rproc *rproc, memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); } +out: kfree(fw_name); return ret; diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/drivers/remoteproc/qcom_mdt_loader.h index e513548e52ec..ff6e45b77326 100644 --- a/drivers/remoteproc/qcom_mdt_loader.h +++ b/drivers/remoteproc/qcom_mdt_loader.h @@ -5,8 +5,9 @@ #define QCOM_MDT_TYPE_HASH (2 << 24) #define QCOM_MDT_RELOCATABLE BIT(27) -int qcom_mdt_load(struct rproc *rproc, const struct firmware *fw, const char *fw_name); - -int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate); +ssize_t qcom_mdt_get_size(const struct firmware *fw); +int qcom_mdt_load(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, void *mem_region, + phys_addr_t mem_phys, size_t mem_size); #endif diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index f158f8243b04..fbb25ea4ae8a 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -153,34 +153,9 @@ void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss, static int wcnss_load(struct rproc *rproc, const struct firmware *fw) { struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; - phys_addr_t fw_addr; - size_t fw_size; - bool relocate; - int ret; - ret = qcom_scm_pas_init_image(WCNSS_PAS_ID, fw->data, fw->size); - if (ret) { - dev_err(&rproc->dev, "invalid firmware metadata\n"); - return ret; - } - - ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate); - if (ret) { - dev_err(&rproc->dev, "failed to parse mdt header\n"); - return ret; - } - - if (relocate) { - wcnss->mem_reloc = fw_addr; - - ret = qcom_scm_pas_mem_setup(WCNSS_PAS_ID, wcnss->mem_phys, fw_size); - if (ret) { - dev_err(&rproc->dev, "unable to setup memory for image\n"); - return ret; - } - } - - return qcom_mdt_load(rproc, fw, rproc->firmware); + return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID, + wcnss->mem_region, wcnss->mem_phys, wcnss->mem_size); } static const struct rproc_fw_ops wcnss_fw_ops = { From 2aad40d911eeb7dcac91c669f2762a28134f0eb1 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 27 Jan 2017 03:12:57 -0800 Subject: [PATCH 18/27] remoteproc: Move qcom_mdt_loader into drivers/soc/qcom With the remoteproc parts cleaned out of the MDT loader we can move it to drivers/soc/qcom. Acked-by: Andy Gross Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 3 --- drivers/remoteproc/Makefile | 1 - drivers/remoteproc/qcom_adsp_pil.c | 2 +- drivers/remoteproc/qcom_q6v5_pil.c | 2 +- drivers/remoteproc/qcom_wcnss.c | 2 +- drivers/soc/qcom/Kconfig | 4 ++++ drivers/soc/qcom/Makefile | 1 + .../{remoteproc/qcom_mdt_loader.c => soc/qcom/mdt_loader.c} | 3 +-- .../qcom_mdt_loader.h => include/linux/soc/qcom/mdt_loader.h | 5 +++++ 9 files changed, 14 insertions(+), 9 deletions(-) rename drivers/{remoteproc/qcom_mdt_loader.c => soc/qcom/mdt_loader.c} (99%) rename drivers/remoteproc/qcom_mdt_loader.h => include/linux/soc/qcom/mdt_loader.h (87%) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 71ea703190c6..555dba04b5ae 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -87,9 +87,6 @@ config QCOM_ADSP_PIL config QCOM_RPROC_COMMON tristate -config QCOM_MDT_LOADER - tristate - config QCOM_Q6V5_PIL tristate "Qualcomm Hexagon V5 Peripherial Image Loader" depends on OF && ARCH_QCOM diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index d4f9525a226d..ffc5e430df27 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o -obj-$(CONFIG_QCOM_MDT_LOADER) += qcom_mdt_loader.o obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index c1ee5c818b42..301b820216f6 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -26,11 +26,11 @@ #include #include #include +#include #include #include #include "qcom_common.h" -#include "qcom_mdt_loader.h" #include "remoteproc_internal.h" struct adsp_data { diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 2e44c06e604a..b129261d7e5e 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -29,12 +29,12 @@ #include #include #include +#include #include #include #include "remoteproc_internal.h" #include "qcom_common.h" -#include "qcom_mdt_loader.h" #include diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index fbb25ea4ae8a..781211c144c6 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -28,12 +28,12 @@ #include #include #include +#include #include #include #include #include "qcom_common.h" -#include "qcom_mdt_loader.h" #include "remoteproc_internal.h" #include "qcom_wcnss.h" diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 461b387d03cc..78b1bb7bcf20 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -10,6 +10,10 @@ config QCOM_GSBI functions for connecting the underlying serial UART, SPI, and I2C devices to the output pins. +config QCOM_MDT_LOADER + tristate + select QCOM_SCM + config QCOM_PM bool "Qualcomm Power Management" depends on ARCH_QCOM && !ARM64 diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index fdd664edf0bd..1f30260b06b8 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o +obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_SMD) += smd.o obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/soc/qcom/mdt_loader.c similarity index 99% rename from drivers/remoteproc/qcom_mdt_loader.c rename to drivers/soc/qcom/mdt_loader.c index 790ab31f31ff..98b2373c3a97 100644 --- a/drivers/remoteproc/qcom_mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -23,8 +23,7 @@ #include #include #include - -#include "qcom_mdt_loader.h" +#include static bool mdt_phdr_valid(const struct elf32_phdr *phdr) { diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h similarity index 87% rename from drivers/remoteproc/qcom_mdt_loader.h rename to include/linux/soc/qcom/mdt_loader.h index ff6e45b77326..f423001db3a9 100644 --- a/drivers/remoteproc/qcom_mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -1,10 +1,15 @@ #ifndef __QCOM_MDT_LOADER_H__ #define __QCOM_MDT_LOADER_H__ +#include + #define QCOM_MDT_TYPE_MASK (7 << 24) #define QCOM_MDT_TYPE_HASH (2 << 24) #define QCOM_MDT_RELOCATABLE BIT(27) +struct device; +struct firmware; + ssize_t qcom_mdt_get_size(const struct firmware *fw); int qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, void *mem_region, From b90fcfcb1378ddab1ee58ec7caaedbba2a8eb7c6 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 27 Jan 2017 07:04:54 -0800 Subject: [PATCH 19/27] remoteproc: qcom: wcnss: Make SMD handling common Move the SMD edge handling to the Qualcomm common file to make it reusable for other Qualcomm remoteproc drivers. Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 50 ++++++++++++++++++++++++++++++++ drivers/remoteproc/qcom_common.h | 15 ++++++++-- drivers/remoteproc/qcom_wcnss.c | 28 +++--------------- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index bd400336e209..bb90481215c6 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -19,10 +19,13 @@ #include #include #include +#include #include "remoteproc_internal.h" #include "qcom_common.h" +#define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) + /** * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc * @rproc: remoteproc handle @@ -42,5 +45,52 @@ struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc, } EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table); +static int smd_subdev_probe(struct rproc_subdev *subdev) +{ + struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); + + smd->edge = qcom_smd_register_edge(smd->dev, smd->node); + + return IS_ERR(smd->edge) ? PTR_ERR(smd->edge) : 0; +} + +static void smd_subdev_remove(struct rproc_subdev *subdev) +{ + struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); + + qcom_smd_unregister_edge(smd->edge); + smd->edge = NULL; +} + +/** + * qcom_add_smd_subdev() - try to add a SMD subdevice to rproc + * @rproc: rproc handle to parent the subdevice + * @smd: reference to a Qualcomm subdev context + */ +void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) +{ + struct device *dev = &rproc->dev; + + smd->node = of_get_child_by_name(dev->parent->of_node, "smd-edge"); + if (!smd->node) + return; + + smd->dev = dev; + rproc_add_subdev(rproc, &smd->subdev, smd_subdev_probe, smd_subdev_remove); +} +EXPORT_SYMBOL_GPL(qcom_add_smd_subdev); + +/** + * qcom_remove_smd_subdev() - remove the smd subdevice from rproc + * @rproc: rproc handle + * @smd: the SMD subdevice to remove + */ +void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) +{ + rproc_remove_subdev(rproc, &smd->subdev); + of_node_put(smd->node); +} +EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); + MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h index caecf27c4ffa..db5c826d5cd4 100644 --- a/drivers/remoteproc/qcom_common.h +++ b/drivers/remoteproc/qcom_common.h @@ -1,11 +1,22 @@ #ifndef __RPROC_QCOM_COMMON_H__ #define __RPROC_QCOM_COMMON_H__ -struct resource_table; -struct rproc; +#include +#include "remoteproc_internal.h" + +struct qcom_rproc_subdev { + struct rproc_subdev subdev; + + struct device *dev; + struct device_node *node; + struct qcom_smd_edge *edge; +}; struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc, const struct firmware *fw, int *tablesz); +void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd); +void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd); + #endif diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 781211c144c6..c7686393d505 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -97,9 +97,7 @@ struct qcom_wcnss { void *mem_region; size_t mem_size; - struct device_node *smd_node; - struct qcom_smd_edge *smd_edge; - struct rproc_subdev smd_subdev; + struct qcom_rproc_subdev smd_subdev; }; static const struct wcnss_data riva_data = { @@ -376,23 +374,6 @@ static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev) return IRQ_HANDLED; } -static int wcnss_smd_probe(struct rproc_subdev *subdev) -{ - struct qcom_wcnss *wcnss = container_of(subdev, struct qcom_wcnss, smd_subdev); - - wcnss->smd_edge = qcom_smd_register_edge(wcnss->dev, wcnss->smd_node); - - return IS_ERR(wcnss->smd_edge) ? PTR_ERR(wcnss->smd_edge) : 0; -} - -static void wcnss_smd_remove(struct rproc_subdev *subdev) -{ - struct qcom_wcnss *wcnss = container_of(subdev, struct qcom_wcnss, smd_subdev); - - qcom_smd_unregister_edge(wcnss->smd_edge); - wcnss->smd_edge = NULL; -} - static int wcnss_init_regulators(struct qcom_wcnss *wcnss, const struct wcnss_vreg_info *info, int num_vregs) @@ -575,9 +556,7 @@ static int wcnss_probe(struct platform_device *pdev) } } - wcnss->smd_node = of_get_child_by_name(pdev->dev.of_node, "smd-edge"); - if (wcnss->smd_node) - rproc_add_subdev(rproc, &wcnss->smd_subdev, wcnss_smd_probe, wcnss_smd_remove); + qcom_add_smd_subdev(rproc, &wcnss->smd_subdev); ret = rproc_add(rproc); if (ret) @@ -597,9 +576,10 @@ static int wcnss_remove(struct platform_device *pdev) of_platform_depopulate(&pdev->dev); - of_node_put(wcnss->smd_node); qcom_smem_state_put(wcnss->state); rproc_del(wcnss->rproc); + + qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev); rproc_free(wcnss->rproc); return 0; From 4b48921a8f74e7dfff5b39ab966c86f99717db3a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sun, 29 Jan 2017 14:05:50 -0800 Subject: [PATCH 20/27] remoteproc: qcom: Use common SMD edge handler Call the common SMD edge handler to instantiate subdevices to bring associated SMD edges up and down as the remoteproc is started and stopped. Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 2 ++ drivers/remoteproc/qcom_adsp_pil.c | 6 ++++++ drivers/remoteproc/qcom_q6v5_pil.c | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 555dba04b5ae..402de7089302 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -76,6 +76,7 @@ config QCOM_ADSP_PIL depends on OF && ARCH_QCOM depends on REMOTEPROC depends on QCOM_SMEM + depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n) select MFD_SYSCON select QCOM_MDT_LOADER select QCOM_RPROC_COMMON @@ -92,6 +93,7 @@ config QCOM_Q6V5_PIL depends on OF && ARCH_QCOM depends on QCOM_SMEM depends on REMOTEPROC + depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n) select MFD_SYSCON select QCOM_RPROC_COMMON select QCOM_SCM diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index 301b820216f6..f1b147c96d44 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -70,6 +70,8 @@ struct qcom_adsp { phys_addr_t mem_reloc; void *mem_region; size_t mem_size; + + struct qcom_rproc_subdev smd_subdev; }; static int adsp_load(struct rproc *rproc, const struct firmware *fw) @@ -404,6 +406,8 @@ static int adsp_probe(struct platform_device *pdev) goto free_rproc; } + qcom_add_smd_subdev(rproc, &adsp->smd_subdev); + ret = rproc_add(rproc); if (ret) goto free_rproc; @@ -422,6 +426,8 @@ static int adsp_remove(struct platform_device *pdev) qcom_smem_state_put(adsp->state); rproc_del(adsp->rproc); + + qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev); rproc_free(adsp->rproc); return 0; diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index b129261d7e5e..26446eb08bd8 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -151,6 +151,8 @@ struct q6v5 { phys_addr_t mpss_reloc; void *mpss_region; size_t mpss_size; + + struct qcom_rproc_subdev smd_subdev; }; static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, @@ -1035,6 +1037,8 @@ static int q6v5_probe(struct platform_device *pdev) goto free_rproc; } + qcom_add_smd_subdev(rproc, &qproc->smd_subdev); + ret = rproc_add(rproc); if (ret) goto free_rproc; @@ -1052,6 +1056,8 @@ static int q6v5_remove(struct platform_device *pdev) struct q6v5 *qproc = platform_get_drvdata(pdev); rproc_del(qproc->rproc); + + qcom_remove_smd_subdev(qproc->rproc, &qproc->smd_subdev); rproc_free(qproc->rproc); return 0; From 38c6fc32387ade2b4ce6ac494ca50b4a312a8d59 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 30 Jan 2017 09:00:22 -0800 Subject: [PATCH 21/27] MAINTAINERS: Add missing rpmsg include path Signed-off-by: Bjorn Andersson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c36976d3bd1a..d46fced63f0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10425,6 +10425,7 @@ S: Maintained F: drivers/rpmsg/ F: Documentation/rpmsg.txt F: include/linux/rpmsg.h +F: include/linux/rpmsg/ RENESAS CLOCK DRIVERS M: Geert Uytterhoeven From 66a66aa74ee262f03432f84de55ae314c391d9f5 Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Thu, 2 Feb 2017 16:04:37 -0800 Subject: [PATCH 22/27] remoteproc: Drop qcom_scm_pas_supported() from adsp_probe() SCM call to check whether Peripheral Authentication Service (PAS) is supported returns false for ADSP on MSM8996. Drop this call from the driver so that the probe() function succeeds for ADSP PIL device. Signed-off-by: Sarangdhar Joshi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_adsp_pil.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index f1b147c96d44..49fe2f807e1d 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -337,11 +337,6 @@ static int adsp_probe(struct platform_device *pdev) if (!qcom_scm_is_available()) return -EPROBE_DEFER; - if (!qcom_scm_pas_supported(desc->pas_id)) { - dev_err(&pdev->dev, "PAS is not available for subsystem\n"); - return -ENXIO; - } - rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops, desc->firmware_name, sizeof(*adsp)); if (!rproc) { From 7a20c64ddb3deeb08bbe1ca8e9bcafd3241a5e0e Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Tue, 24 Jan 2017 15:13:00 -0800 Subject: [PATCH 23/27] remoteproc: Reduce asynchronous request_firmware to auto-boot only The rproc_add_virtio_devices() requests firmware asynchronously and triggers boot if the auto_boot flag is set. However, this asynchronous call seems to be redundant for non auto-boot scenario since the rproc_boot() would call request_firmware() anyways. Move the auto_boot check to rproc_add() so that a redundant call to _request_firmware can be avoided for non auto-boot case. Signed-off-by: Sarangdhar Joshi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index a7ee05006cca..a112f5969d4a 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -972,9 +972,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) { struct rproc *rproc = context; - /* if rproc is marked always-on, request it to boot */ - if (rproc->auto_boot) - rproc_boot(rproc); + rproc_boot(rproc); release_firmware(fw); } @@ -1286,9 +1284,13 @@ int rproc_add(struct rproc *rproc) /* create debugfs entries */ rproc_create_debug_dir(rproc); - ret = rproc_add_virtio_devices(rproc); - if (ret < 0) - return ret; + + /* if rproc is marked always-on, request it to boot */ + if (rproc->auto_boot) { + ret = rproc_add_virtio_devices(rproc); + if (ret < 0) + return ret; + } /* expose to rproc_get_by_phandle users */ mutex_lock(&rproc_list_mutex); From 5e6533f72ce849bf49aaee96429bbe3558789d08 Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi Date: Tue, 24 Jan 2017 15:13:01 -0800 Subject: [PATCH 24/27] remoteproc: Modify the function names The functions rproc_add_virtio_devices() and rproc_fw_config_virtio() are reduced to trigger auto-boot only. Modify these function names and related comments to reflect their current state. This patch does not add any functional change. Signed-off-by: Sarangdhar Joshi Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index a112f5969d4a..3dabb20b8d5d 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -961,14 +961,14 @@ clean_up: } /* - * take a firmware and look for virtio devices to register. + * take a firmware and boot it up. * * Note: this function is called asynchronously upon registration of the * remote processor (so we must wait until it completes before we try * to unregister the device. one other option is just to use kref here, * that might be cleaner). */ -static void rproc_fw_config_virtio(const struct firmware *fw, void *context) +static void rproc_auto_boot_callback(const struct firmware *fw, void *context) { struct rproc *rproc = context; @@ -977,21 +977,17 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) release_firmware(fw); } -static int rproc_add_virtio_devices(struct rproc *rproc) +static int rproc_trigger_auto_boot(struct rproc *rproc) { int ret; /* - * We must retrieve early virtio configuration info from - * the firmware (e.g. whether to register a virtio device, - * what virtio features does it support, ...). - * * We're initiating an asynchronous firmware loading, so we can * be built-in kernel code, without hanging the boot process. */ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, rproc->firmware, &rproc->dev, GFP_KERNEL, - rproc, rproc_fw_config_virtio); + rproc, rproc_auto_boot_callback); if (ret < 0) dev_err(&rproc->dev, "request_firmware_nowait err: %d\n", ret); @@ -1287,7 +1283,7 @@ int rproc_add(struct rproc *rproc) /* if rproc is marked always-on, request it to boot */ if (rproc->auto_boot) { - ret = rproc_add_virtio_devices(rproc); + ret = rproc_trigger_auto_boot(rproc); if (ret < 0) return ret; } From 3e49ecf6b49c31b70235d260b957376c00265c1e Mon Sep 17 00:00:00 2001 From: Loic Pallardy Date: Tue, 31 Jan 2017 13:35:53 +0100 Subject: [PATCH 25/27] remoteproc: st: correct probe error management Associated clock is prepared in st_rproc_parse_dt function. it should be unprepared in case of error during probing. Signed-off-by: Loic Pallardy Signed-off-by: Bjorn Andersson --- drivers/remoteproc/st_remoteproc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index f21787b602e3..1468ba213811 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -247,7 +247,7 @@ static int st_rproc_probe(struct platform_device *pdev) enabled = st_rproc_state(pdev); if (enabled < 0) { ret = enabled; - goto free_rproc; + goto free_clk; } if (enabled) { @@ -259,10 +259,12 @@ static int st_rproc_probe(struct platform_device *pdev) ret = rproc_add(rproc); if (ret) - goto free_rproc; + goto free_clk; return 0; +free_clk: + clk_unprepare(ddata->clk); free_rproc: rproc_free(rproc); return ret; From 231c8dfd1a9ff530869e1327ba4168dbe592f3f9 Mon Sep 17 00:00:00 2001 From: Loic Pallardy Date: Tue, 31 Jan 2017 13:35:54 +0100 Subject: [PATCH 26/27] remoteproc: st: add virtio communication support This patch provides virtio communication support based on mailbox for ST co-processors. Signed-off-by: Loic Pallardy Signed-off-by: Ludovic Barre Signed-off-by: Lee Jones Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 3 + drivers/remoteproc/st_remoteproc.c | 113 ++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 402de7089302..65f86bc24c07 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -118,6 +118,9 @@ config ST_REMOTEPROC tristate "ST remoteproc support" depends on ARCH_STI depends on REMOTEPROC + select MAILBOX + select STI_MBOX + select RPMSG_VIRTIO help Say y here to support ST's adjunct processors via the remote processor framework. diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index 1468ba213811..d534bf23dc56 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,16 @@ #include #include +#include "remoteproc_internal.h" + +#define ST_RPROC_VQ0 0 +#define ST_RPROC_VQ1 1 +#define ST_RPROC_MAX_VRING 2 + +#define MBOX_RX 0 +#define MBOX_TX 1 +#define MBOX_MAX 2 + struct st_rproc_config { bool sw_reset; bool pwr_reset; @@ -39,8 +50,47 @@ struct st_rproc { u32 clk_rate; struct regmap *boot_base; u32 boot_offset; + struct mbox_chan *mbox_chan[ST_RPROC_MAX_VRING * MBOX_MAX]; + struct mbox_client mbox_client_vq0; + struct mbox_client mbox_client_vq1; }; +static void st_rproc_mbox_callback(struct device *dev, u32 msg) +{ + struct rproc *rproc = dev_get_drvdata(dev); + + if (rproc_vq_interrupt(rproc, msg) == IRQ_NONE) + dev_dbg(dev, "no message was found in vqid %d\n", msg); +} + +static +void st_rproc_mbox_callback_vq0(struct mbox_client *mbox_client, void *data) +{ + st_rproc_mbox_callback(mbox_client->dev, 0); +} + +static +void st_rproc_mbox_callback_vq1(struct mbox_client *mbox_client, void *data) +{ + st_rproc_mbox_callback(mbox_client->dev, 1); +} + +static void st_rproc_kick(struct rproc *rproc, int vqid) +{ + struct st_rproc *ddata = rproc->priv; + struct device *dev = rproc->dev.parent; + int ret; + + /* send the index of the triggered virtqueue in the mailbox payload */ + if (WARN_ON(vqid >= ST_RPROC_MAX_VRING)) + return; + + ret = mbox_send_message(ddata->mbox_chan[vqid * MBOX_MAX + MBOX_TX], + (void *)&vqid); + if (ret < 0) + dev_err(dev, "failed to send message via mbox: %d\n", ret); +} + static int st_rproc_start(struct rproc *rproc) { struct st_rproc *ddata = rproc->priv; @@ -108,6 +158,7 @@ static int st_rproc_stop(struct rproc *rproc) } static const struct rproc_ops st_rproc_ops = { + .kick = st_rproc_kick, .start = st_rproc_start, .stop = st_rproc_stop, }; @@ -221,8 +272,9 @@ static int st_rproc_probe(struct platform_device *pdev) struct st_rproc *ddata; struct device_node *np = dev->of_node; struct rproc *rproc; + struct mbox_chan *chan; int enabled; - int ret; + int ret, i; match = of_match_device(st_rproc_match, dev); if (!match || !match->data) { @@ -257,12 +309,65 @@ static int st_rproc_probe(struct platform_device *pdev) clk_set_rate(ddata->clk, ddata->clk_rate); } + if (of_get_property(np, "mbox-names", NULL)) { + ddata->mbox_client_vq0.dev = dev; + ddata->mbox_client_vq0.tx_done = NULL; + ddata->mbox_client_vq0.tx_block = false; + ddata->mbox_client_vq0.knows_txdone = false; + ddata->mbox_client_vq0.rx_callback = st_rproc_mbox_callback_vq0; + + ddata->mbox_client_vq1.dev = dev; + ddata->mbox_client_vq1.tx_done = NULL; + ddata->mbox_client_vq1.tx_block = false; + ddata->mbox_client_vq1.knows_txdone = false; + ddata->mbox_client_vq1.rx_callback = st_rproc_mbox_callback_vq1; + + /* + * To control a co-processor without IPC mechanism. + * This driver can be used without mbox and rpmsg. + */ + chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_rx"); + if (IS_ERR(chan)) { + dev_err(&rproc->dev, "failed to request mbox chan 0\n"); + ret = PTR_ERR(chan); + goto free_clk; + } + ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_RX] = chan; + + chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_tx"); + if (IS_ERR(chan)) { + dev_err(&rproc->dev, "failed to request mbox chan 0\n"); + ret = PTR_ERR(chan); + goto free_mbox; + } + ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_TX] = chan; + + chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_rx"); + if (IS_ERR(chan)) { + dev_err(&rproc->dev, "failed to request mbox chan 1\n"); + ret = PTR_ERR(chan); + goto free_mbox; + } + ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_RX] = chan; + + chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_tx"); + if (IS_ERR(chan)) { + dev_err(&rproc->dev, "failed to request mbox chan 1\n"); + ret = PTR_ERR(chan); + goto free_mbox; + } + ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_TX] = chan; + } + ret = rproc_add(rproc); if (ret) - goto free_clk; + goto free_mbox; return 0; +free_mbox: + for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++) + mbox_free_channel(ddata->mbox_chan[i]); free_clk: clk_unprepare(ddata->clk); free_rproc: @@ -274,6 +379,7 @@ static int st_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); struct st_rproc *ddata = rproc->priv; + int i; rproc_del(rproc); @@ -281,6 +387,9 @@ static int st_rproc_remove(struct platform_device *pdev) of_reserved_mem_device_release(&pdev->dev); + for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++) + mbox_free_channel(ddata->mbox_chan[i]); + rproc_free(rproc); return 0; From 01625cc5e65f420dbea57f7de6b9552a0f807a84 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 15 Feb 2017 14:00:41 -0800 Subject: [PATCH 27/27] remoteproc: qcom: mdt_loader: Use signed type for offset In the transition from using rproc_da_to_va(), the type of the load offset became unsigned. This causes the subsequent check to let negative values less than p_memsz + mem_size through and we write outside of the buffer. Change the type back to a signed value to catch this. Fixes: 7f0dd07a9b29 ("remoteproc: qcom: mdt_loader: Refactor MDT loader") Fixes: e7fd25226295 ("remoteproc: qcom: q6v5: Decouple driver from MDT loader") Reported-by: Dan Carpenter Reported-by: Stanimir Varbanov Acked-by: Andy Gross Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pil.c | 2 +- drivers/soc/qcom/mdt_loader.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 26446eb08bd8..8fd697a3cf8f 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -502,7 +502,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc) phys_addr_t max_addr = 0; bool relocate = false; char seg_name[10]; - size_t offset; + ssize_t offset; size_t size; void *ptr; int ret; diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 98b2373c3a97..bd63df0d14e0 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -98,7 +98,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; phys_addr_t max_addr = 0; size_t fw_name_len; - size_t offset; + ssize_t offset; char *fw_name; bool relocate = false; void *ptr;