diff options
-rw-r--r-- | Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt | 132 | ||||
-rw-r--r-- | Documentation/remoteproc.txt | 6 | ||||
-rw-r--r-- | drivers/remoteproc/Kconfig | 16 | ||||
-rw-r--r-- | drivers/remoteproc/Makefile | 2 | ||||
-rw-r--r-- | drivers/remoteproc/da8xx_remoteproc.c | 6 | ||||
-rw-r--r-- | drivers/remoteproc/omap_remoteproc.c | 9 | ||||
-rw-r--r-- | drivers/remoteproc/qcom_q6v5_pil.c | 8 | ||||
-rw-r--r-- | drivers/remoteproc/qcom_wcnss.c | 624 | ||||
-rw-r--r-- | drivers/remoteproc/qcom_wcnss.h | 22 | ||||
-rw-r--r-- | drivers/remoteproc/qcom_wcnss_iris.c | 188 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 248 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_debugfs.c | 20 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_elf_loader.c | 6 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_internal.h | 15 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_virtio.c | 35 | ||||
-rw-r--r-- | drivers/remoteproc/st_remoteproc.c | 4 | ||||
-rw-r--r-- | drivers/remoteproc/ste_modem_rproc.c | 4 | ||||
-rw-r--r-- | drivers/remoteproc/wkup_m3_rproc.c | 6 | ||||
-rw-r--r-- | include/linux/platform_data/remoteproc-omap.h | 6 | ||||
-rw-r--r-- | include/linux/remoteproc.h | 16 |
20 files changed, 1168 insertions, 205 deletions
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt new file mode 100644 index 000000000000..0d2361ebe3d7 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.txt | |||
@@ -0,0 +1,132 @@ | |||
1 | Qualcomm WCNSS Peripheral Image Loader | ||
2 | |||
3 | This document defines the binding for a component that loads and boots firmware | ||
4 | on the Qualcomm WCNSS core. | ||
5 | |||
6 | - compatible: | ||
7 | Usage: required | ||
8 | Value type: <string> | ||
9 | Definition: must be one of: | ||
10 | "qcom,riva-pil", | ||
11 | "qcom,pronto-v1-pil", | ||
12 | "qcom,pronto-v2-pil" | ||
13 | |||
14 | - reg: | ||
15 | Usage: required | ||
16 | Value type: <prop-encoded-array> | ||
17 | Definition: must specify the base address and size of the CCU, DXE and | ||
18 | PMU register blocks | ||
19 | |||
20 | - reg-names: | ||
21 | Usage: required | ||
22 | Value type: <stringlist> | ||
23 | Definition: must be "ccu", "dxe", "pmu" | ||
24 | |||
25 | - interrupts-extended: | ||
26 | Usage: required | ||
27 | Value type: <prop-encoded-array> | ||
28 | Definition: must list the watchdog and fatal IRQs and may specify the | ||
29 | ready, handover and stop-ack IRQs | ||
30 | |||
31 | - interrupt-names: | ||
32 | Usage: required | ||
33 | Value type: <stringlist> | ||
34 | Definition: should be "wdog", "fatal", optionally followed by "ready", | ||
35 | "handover", "stop-ack" | ||
36 | |||
37 | - vddmx-supply: | ||
38 | - vddcx-supply: | ||
39 | - vddpx-supply: | ||
40 | Usage: required | ||
41 | Value type: <phandle> | ||
42 | Definition: reference to the regulators to be held on behalf of the | ||
43 | booting of the WCNSS core | ||
44 | |||
45 | - qcom,smem-states: | ||
46 | Usage: optional | ||
47 | Value type: <prop-encoded-array> | ||
48 | Definition: reference to the SMEM state used to indicate to WCNSS that | ||
49 | it should shut down | ||
50 | |||
51 | - qcom,smem-state-names: | ||
52 | Usage: optional | ||
53 | Value type: <stringlist> | ||
54 | Definition: should be "stop" | ||
55 | |||
56 | - memory-region: | ||
57 | Usage: required | ||
58 | Value type: <prop-encoded-array> | ||
59 | Definition: reference to reserved-memory node for the remote processor | ||
60 | see ../reserved-memory/reserved-memory.txt | ||
61 | |||
62 | = SUBNODES | ||
63 | A single subnode of the WCNSS PIL describes the attached rf module and its | ||
64 | resource dependencies. | ||
65 | |||
66 | - compatible: | ||
67 | Usage: required | ||
68 | Value type: <string> | ||
69 | Definition: must be one of: | ||
70 | "qcom,wcn3620", | ||
71 | "qcom,wcn3660", | ||
72 | "qcom,wcn3680" | ||
73 | |||
74 | - clocks: | ||
75 | Usage: required | ||
76 | Value type: <prop-encoded-array> | ||
77 | Definition: should specify the xo clock and optionally the rf clock | ||
78 | |||
79 | - clock-names: | ||
80 | Usage: required | ||
81 | Value type: <stringlist> | ||
82 | Definition: should be "xo", optionally followed by "rf" | ||
83 | |||
84 | - vddxo-supply: | ||
85 | - vddrfa-supply: | ||
86 | - vddpa-supply: | ||
87 | - vdddig-supply: | ||
88 | Usage: required | ||
89 | Value type: <phandle> | ||
90 | Definition: reference to the regulators to be held on behalf of the | ||
91 | booting of the WCNSS core | ||
92 | |||
93 | = EXAMPLE | ||
94 | The following example describes the resources needed to boot control the WCNSS, | ||
95 | with attached WCN3680, as it is commonly found on MSM8974 boards. | ||
96 | |||
97 | pronto@fb204000 { | ||
98 | compatible = "qcom,pronto-v2-pil"; | ||
99 | reg = <0xfb204000 0x2000>, <0xfb202000 0x1000>, <0xfb21b000 0x3000>; | ||
100 | reg-names = "ccu", "dxe", "pmu"; | ||
101 | |||
102 | interrupts-extended = <&intc 0 149 1>, | ||
103 | <&wcnss_smp2p_slave 0 0>, | ||
104 | <&wcnss_smp2p_slave 1 0>, | ||
105 | <&wcnss_smp2p_slave 2 0>, | ||
106 | <&wcnss_smp2p_slave 3 0>; | ||
107 | interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack"; | ||
108 | |||
109 | vddmx-supply = <&pm8841_s1>; | ||
110 | vddcx-supply = <&pm8841_s2>; | ||
111 | vddpx-supply = <&pm8941_s3>; | ||
112 | |||
113 | qcom,smem-states = <&wcnss_smp2p_out 0>; | ||
114 | qcom,smem-state-names = "stop"; | ||
115 | |||
116 | memory-region = <&wcnss_region>; | ||
117 | |||
118 | pinctrl-names = "default"; | ||
119 | pinctrl-0 = <&wcnss_pin_a>; | ||
120 | |||
121 | iris { | ||
122 | compatible = "qcom,wcn3680"; | ||
123 | |||
124 | clocks = <&rpmcc RPM_CXO_CLK_SRC>, <&rpmcc RPM_CXO_A2>; | ||
125 | clock-names = "xo", "rf"; | ||
126 | |||
127 | vddxo-supply = <&pm8941_l6>; | ||
128 | vddrfa-supply = <&pm8941_l11>; | ||
129 | vddpa-supply = <&pm8941_l19>; | ||
130 | vdddig-supply = <&pm8941_s3>; | ||
131 | }; | ||
132 | }; | ||
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt index ef0219fa4bb4..f07597482351 100644 --- a/Documentation/remoteproc.txt +++ b/Documentation/remoteproc.txt | |||
@@ -101,9 +101,9 @@ int dummy_rproc_example(struct rproc *my_rproc) | |||
101 | On success, the new rproc is returned, and on failure, NULL. | 101 | On success, the new rproc is returned, and on failure, NULL. |
102 | 102 | ||
103 | Note: _never_ directly deallocate @rproc, even if it was not registered | 103 | Note: _never_ directly deallocate @rproc, even if it was not registered |
104 | yet. Instead, when you need to unroll rproc_alloc(), use rproc_put(). | 104 | yet. Instead, when you need to unroll rproc_alloc(), use rproc_free(). |
105 | 105 | ||
106 | void rproc_put(struct rproc *rproc) | 106 | void rproc_free(struct rproc *rproc) |
107 | - Free an rproc handle that was allocated by rproc_alloc. | 107 | - Free an rproc handle that was allocated by rproc_alloc. |
108 | This function essentially unrolls rproc_alloc(), by decrementing the | 108 | This function essentially unrolls rproc_alloc(), by decrementing the |
109 | rproc's refcount. It doesn't directly free rproc; that would happen | 109 | rproc's refcount. It doesn't directly free rproc; that would happen |
@@ -131,7 +131,7 @@ int dummy_rproc_example(struct rproc *my_rproc) | |||
131 | has completed successfully. | 131 | has completed successfully. |
132 | 132 | ||
133 | After rproc_del() returns, @rproc is still valid, and its | 133 | After rproc_del() returns, @rproc is still valid, and its |
134 | last refcount should be decremented by calling rproc_put(). | 134 | last refcount should be decremented by calling rproc_free(). |
135 | 135 | ||
136 | Returns 0 on success and -EINVAL if @rproc isn't valid. | 136 | Returns 0 on success and -EINVAL if @rproc isn't valid. |
137 | 137 | ||
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 1a8bf76a925f..f76b3b1dca1a 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig | |||
@@ -91,6 +91,22 @@ config QCOM_Q6V5_PIL | |||
91 | Say y here to support the Qualcomm Peripherial Image Loader for the | 91 | Say y here to support the Qualcomm Peripherial Image Loader for the |
92 | Hexagon V5 based remote processors. | 92 | Hexagon V5 based remote processors. |
93 | 93 | ||
94 | config QCOM_WCNSS_IRIS | ||
95 | tristate | ||
96 | depends on OF && ARCH_QCOM | ||
97 | |||
98 | config QCOM_WCNSS_PIL | ||
99 | tristate "Qualcomm WCNSS Peripheral Image Loader" | ||
100 | depends on OF && ARCH_QCOM | ||
101 | depends on QCOM_SMEM | ||
102 | select QCOM_MDT_LOADER | ||
103 | select QCOM_SCM | ||
104 | select QCOM_WCNSS_IRIS | ||
105 | select REMOTEPROC | ||
106 | help | ||
107 | Say y here to support the Peripheral Image Loader for the Qualcomm | ||
108 | Wireless Connectivity Subsystem. | ||
109 | |||
94 | config ST_REMOTEPROC | 110 | config ST_REMOTEPROC |
95 | tristate "ST remoteproc support" | 111 | tristate "ST remoteproc support" |
96 | depends on ARCH_STI | 112 | depends on ARCH_STI |
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 92d3758bd15c..6dfb62ed643f 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile | |||
@@ -13,4 +13,6 @@ obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o | |||
13 | obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o | 13 | obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o |
14 | obj-$(CONFIG_QCOM_MDT_LOADER) += qcom_mdt_loader.o | 14 | obj-$(CONFIG_QCOM_MDT_LOADER) += qcom_mdt_loader.o |
15 | obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o | 15 | obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o |
16 | obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o | ||
17 | obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o | ||
16 | obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o | 18 | obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o |
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 009e56f67de2..1afac8f31be0 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c | |||
@@ -147,7 +147,7 @@ static void da8xx_rproc_kick(struct rproc *rproc, int vqid) | |||
147 | { | 147 | { |
148 | struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; | 148 | struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; |
149 | 149 | ||
150 | /* Interupt remote proc */ | 150 | /* Interrupt remote proc */ |
151 | writel(SYSCFG_CHIPSIG2, drproc->chipsig); | 151 | writel(SYSCFG_CHIPSIG2, drproc->chipsig); |
152 | } | 152 | } |
153 | 153 | ||
@@ -261,7 +261,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) | |||
261 | return 0; | 261 | return 0; |
262 | 262 | ||
263 | free_rproc: | 263 | free_rproc: |
264 | rproc_put(rproc); | 264 | rproc_free(rproc); |
265 | 265 | ||
266 | return ret; | 266 | return ret; |
267 | } | 267 | } |
@@ -290,7 +290,7 @@ static int da8xx_rproc_remove(struct platform_device *pdev) | |||
290 | disable_irq(drproc->irq); | 290 | disable_irq(drproc->irq); |
291 | 291 | ||
292 | rproc_del(rproc); | 292 | rproc_del(rproc); |
293 | rproc_put(rproc); | 293 | rproc_free(rproc); |
294 | 294 | ||
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index b74368a91235..fa63bf2eb885 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c | |||
@@ -96,7 +96,8 @@ static void omap_rproc_kick(struct rproc *rproc, int vqid) | |||
96 | /* send the index of the triggered virtqueue in the mailbox payload */ | 96 | /* send the index of the triggered virtqueue in the mailbox payload */ |
97 | ret = mbox_send_message(oproc->mbox, (void *)vqid); | 97 | ret = mbox_send_message(oproc->mbox, (void *)vqid); |
98 | if (ret < 0) | 98 | if (ret < 0) |
99 | dev_err(dev, "omap_mbox_msg_send failed: %d\n", ret); | 99 | dev_err(dev, "failed to send mailbox message, status = %d\n", |
100 | ret); | ||
100 | } | 101 | } |
101 | 102 | ||
102 | /* | 103 | /* |
@@ -196,7 +197,7 @@ static int omap_rproc_probe(struct platform_device *pdev) | |||
196 | } | 197 | } |
197 | 198 | ||
198 | rproc = rproc_alloc(&pdev->dev, pdata->name, &omap_rproc_ops, | 199 | rproc = rproc_alloc(&pdev->dev, pdata->name, &omap_rproc_ops, |
199 | pdata->firmware, sizeof(*oproc)); | 200 | pdata->firmware, sizeof(*oproc)); |
200 | if (!rproc) | 201 | if (!rproc) |
201 | return -ENOMEM; | 202 | return -ENOMEM; |
202 | 203 | ||
@@ -214,7 +215,7 @@ static int omap_rproc_probe(struct platform_device *pdev) | |||
214 | return 0; | 215 | return 0; |
215 | 216 | ||
216 | free_rproc: | 217 | free_rproc: |
217 | rproc_put(rproc); | 218 | rproc_free(rproc); |
218 | return ret; | 219 | return ret; |
219 | } | 220 | } |
220 | 221 | ||
@@ -223,7 +224,7 @@ static int omap_rproc_remove(struct platform_device *pdev) | |||
223 | struct rproc *rproc = platform_get_drvdata(pdev); | 224 | struct rproc *rproc = platform_get_drvdata(pdev); |
224 | 225 | ||
225 | rproc_del(rproc); | 226 | rproc_del(rproc); |
226 | rproc_put(rproc); | 227 | rproc_free(rproc); |
227 | 228 | ||
228 | return 0; | 229 | return 0; |
229 | } | 230 | } |
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 2a1b2c7d8f2c..2e0caaaa766a 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c | |||
@@ -863,8 +863,10 @@ static int q6v5_probe(struct platform_device *pdev) | |||
863 | goto free_rproc; | 863 | goto free_rproc; |
864 | 864 | ||
865 | qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit); | 865 | qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit); |
866 | if (IS_ERR(qproc->state)) | 866 | if (IS_ERR(qproc->state)) { |
867 | ret = PTR_ERR(qproc->state); | ||
867 | goto free_rproc; | 868 | goto free_rproc; |
869 | } | ||
868 | 870 | ||
869 | ret = rproc_add(rproc); | 871 | ret = rproc_add(rproc); |
870 | if (ret) | 872 | if (ret) |
@@ -873,7 +875,7 @@ static int q6v5_probe(struct platform_device *pdev) | |||
873 | return 0; | 875 | return 0; |
874 | 876 | ||
875 | free_rproc: | 877 | free_rproc: |
876 | rproc_put(rproc); | 878 | rproc_free(rproc); |
877 | 879 | ||
878 | return ret; | 880 | return ret; |
879 | } | 881 | } |
@@ -883,7 +885,7 @@ static int q6v5_remove(struct platform_device *pdev) | |||
883 | struct q6v5 *qproc = platform_get_drvdata(pdev); | 885 | struct q6v5 *qproc = platform_get_drvdata(pdev); |
884 | 886 | ||
885 | rproc_del(qproc->rproc); | 887 | rproc_del(qproc->rproc); |
886 | rproc_put(qproc->rproc); | 888 | rproc_free(qproc->rproc); |
887 | 889 | ||
888 | return 0; | 890 | return 0; |
889 | } | 891 | } |
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c new file mode 100644 index 000000000000..f5cedeaafba1 --- /dev/null +++ b/drivers/remoteproc/qcom_wcnss.c | |||
@@ -0,0 +1,624 @@ | |||
1 | /* | ||
2 | * Qualcomm Wireless Connectivity Subsystem Peripheral Image Loader | ||
3 | * | ||
4 | * Copyright (C) 2016 Linaro Ltd | ||
5 | * Copyright (C) 2014 Sony Mobile Communications AB | ||
6 | * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/firmware.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/of_address.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/qcom_scm.h> | ||
29 | #include <linux/regulator/consumer.h> | ||
30 | #include <linux/remoteproc.h> | ||
31 | #include <linux/soc/qcom/smem.h> | ||
32 | #include <linux/soc/qcom/smem_state.h> | ||
33 | |||
34 | #include "qcom_mdt_loader.h" | ||
35 | #include "remoteproc_internal.h" | ||
36 | #include "qcom_wcnss.h" | ||
37 | |||
38 | #define WCNSS_CRASH_REASON_SMEM 422 | ||
39 | #define WCNSS_FIRMWARE_NAME "wcnss.mdt" | ||
40 | #define WCNSS_PAS_ID 6 | ||
41 | |||
42 | #define WCNSS_SPARE_NVBIN_DLND BIT(25) | ||
43 | |||
44 | #define WCNSS_PMU_IRIS_XO_CFG BIT(3) | ||
45 | #define WCNSS_PMU_IRIS_XO_EN BIT(4) | ||
46 | #define WCNSS_PMU_GC_BUS_MUX_SEL_TOP BIT(5) | ||
47 | #define WCNSS_PMU_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */ | ||
48 | |||
49 | #define WCNSS_PMU_IRIS_RESET BIT(7) | ||
50 | #define WCNSS_PMU_IRIS_RESET_STS BIT(8) /* 1: in progress, 0: done */ | ||
51 | #define WCNSS_PMU_IRIS_XO_READ BIT(9) | ||
52 | #define WCNSS_PMU_IRIS_XO_READ_STS BIT(10) | ||
53 | |||
54 | #define WCNSS_PMU_XO_MODE_MASK GENMASK(2, 1) | ||
55 | #define WCNSS_PMU_XO_MODE_19p2 0 | ||
56 | #define WCNSS_PMU_XO_MODE_48 3 | ||
57 | |||
58 | struct wcnss_data { | ||
59 | size_t pmu_offset; | ||
60 | size_t spare_offset; | ||
61 | |||
62 | const struct wcnss_vreg_info *vregs; | ||
63 | size_t num_vregs; | ||
64 | }; | ||
65 | |||
66 | struct qcom_wcnss { | ||
67 | struct device *dev; | ||
68 | struct rproc *rproc; | ||
69 | |||
70 | void __iomem *pmu_cfg; | ||
71 | void __iomem *spare_out; | ||
72 | |||
73 | bool use_48mhz_xo; | ||
74 | |||
75 | int wdog_irq; | ||
76 | int fatal_irq; | ||
77 | int ready_irq; | ||
78 | int handover_irq; | ||
79 | int stop_ack_irq; | ||
80 | |||
81 | struct qcom_smem_state *state; | ||
82 | unsigned stop_bit; | ||
83 | |||
84 | struct mutex iris_lock; | ||
85 | struct qcom_iris *iris; | ||
86 | |||
87 | struct regulator_bulk_data *vregs; | ||
88 | size_t num_vregs; | ||
89 | |||
90 | struct completion start_done; | ||
91 | struct completion stop_done; | ||
92 | |||
93 | phys_addr_t mem_phys; | ||
94 | phys_addr_t mem_reloc; | ||
95 | void *mem_region; | ||
96 | size_t mem_size; | ||
97 | }; | ||
98 | |||
99 | static const struct wcnss_data riva_data = { | ||
100 | .pmu_offset = 0x28, | ||
101 | .spare_offset = 0xb4, | ||
102 | |||
103 | .vregs = (struct wcnss_vreg_info[]) { | ||
104 | { "vddmx", 1050000, 1150000, 0 }, | ||
105 | { "vddcx", 1050000, 1150000, 0 }, | ||
106 | { "vddpx", 1800000, 1800000, 0 }, | ||
107 | }, | ||
108 | .num_vregs = 3, | ||
109 | }; | ||
110 | |||
111 | static const struct wcnss_data pronto_v1_data = { | ||
112 | .pmu_offset = 0x1004, | ||
113 | .spare_offset = 0x1088, | ||
114 | |||
115 | .vregs = (struct wcnss_vreg_info[]) { | ||
116 | { "vddmx", 950000, 1150000, 0 }, | ||
117 | { "vddcx", .super_turbo = true}, | ||
118 | { "vddpx", 1800000, 1800000, 0 }, | ||
119 | }, | ||
120 | .num_vregs = 3, | ||
121 | }; | ||
122 | |||
123 | static const struct wcnss_data pronto_v2_data = { | ||
124 | .pmu_offset = 0x1004, | ||
125 | .spare_offset = 0x1088, | ||
126 | |||
127 | .vregs = (struct wcnss_vreg_info[]) { | ||
128 | { "vddmx", 1287500, 1287500, 0 }, | ||
129 | { "vddcx", .super_turbo = true }, | ||
130 | { "vddpx", 1800000, 1800000, 0 }, | ||
131 | }, | ||
132 | .num_vregs = 3, | ||
133 | }; | ||
134 | |||
135 | void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss, | ||
136 | struct qcom_iris *iris, | ||
137 | bool use_48mhz_xo) | ||
138 | { | ||
139 | mutex_lock(&wcnss->iris_lock); | ||
140 | |||
141 | wcnss->iris = iris; | ||
142 | wcnss->use_48mhz_xo = use_48mhz_xo; | ||
143 | |||
144 | mutex_unlock(&wcnss->iris_lock); | ||
145 | } | ||
146 | EXPORT_SYMBOL_GPL(qcom_wcnss_assign_iris); | ||
147 | |||
148 | static int wcnss_load(struct rproc *rproc, const struct firmware *fw) | ||
149 | { | ||
150 | struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; | ||
151 | phys_addr_t fw_addr; | ||
152 | size_t fw_size; | ||
153 | bool relocate; | ||
154 | int ret; | ||
155 | |||
156 | ret = qcom_scm_pas_init_image(WCNSS_PAS_ID, fw->data, fw->size); | ||
157 | if (ret) { | ||
158 | dev_err(&rproc->dev, "invalid firmware metadata\n"); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate); | ||
163 | if (ret) { | ||
164 | dev_err(&rproc->dev, "failed to parse mdt header\n"); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | if (relocate) { | ||
169 | wcnss->mem_reloc = fw_addr; | ||
170 | |||
171 | ret = qcom_scm_pas_mem_setup(WCNSS_PAS_ID, wcnss->mem_phys, fw_size); | ||
172 | if (ret) { | ||
173 | dev_err(&rproc->dev, "unable to setup memory for image\n"); | ||
174 | return ret; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | return qcom_mdt_load(rproc, fw, rproc->firmware); | ||
179 | } | ||
180 | |||
181 | static const struct rproc_fw_ops wcnss_fw_ops = { | ||
182 | .find_rsc_table = qcom_mdt_find_rsc_table, | ||
183 | .load = wcnss_load, | ||
184 | }; | ||
185 | |||
186 | static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss) | ||
187 | { | ||
188 | u32 val; | ||
189 | |||
190 | /* Indicate NV download capability */ | ||
191 | val = readl(wcnss->spare_out); | ||
192 | val |= WCNSS_SPARE_NVBIN_DLND; | ||
193 | writel(val, wcnss->spare_out); | ||
194 | } | ||
195 | |||
196 | static void wcnss_configure_iris(struct qcom_wcnss *wcnss) | ||
197 | { | ||
198 | u32 val; | ||
199 | |||
200 | /* Clear PMU cfg register */ | ||
201 | writel(0, wcnss->pmu_cfg); | ||
202 | |||
203 | val = WCNSS_PMU_GC_BUS_MUX_SEL_TOP | WCNSS_PMU_IRIS_XO_EN; | ||
204 | writel(val, wcnss->pmu_cfg); | ||
205 | |||
206 | /* Clear XO_MODE */ | ||
207 | val &= ~WCNSS_PMU_XO_MODE_MASK; | ||
208 | if (wcnss->use_48mhz_xo) | ||
209 | val |= WCNSS_PMU_XO_MODE_48 << 1; | ||
210 | else | ||
211 | val |= WCNSS_PMU_XO_MODE_19p2 << 1; | ||
212 | writel(val, wcnss->pmu_cfg); | ||
213 | |||
214 | /* Reset IRIS */ | ||
215 | val |= WCNSS_PMU_IRIS_RESET; | ||
216 | writel(val, wcnss->pmu_cfg); | ||
217 | |||
218 | /* Wait for PMU.iris_reg_reset_sts */ | ||
219 | while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_RESET_STS) | ||
220 | cpu_relax(); | ||
221 | |||
222 | /* Clear IRIS reset */ | ||
223 | val &= ~WCNSS_PMU_IRIS_RESET; | ||
224 | writel(val, wcnss->pmu_cfg); | ||
225 | |||
226 | /* Start IRIS XO configuration */ | ||
227 | val |= WCNSS_PMU_IRIS_XO_CFG; | ||
228 | writel(val, wcnss->pmu_cfg); | ||
229 | |||
230 | /* Wait for XO configuration to finish */ | ||
231 | while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_XO_CFG_STS) | ||
232 | cpu_relax(); | ||
233 | |||
234 | /* Stop IRIS XO configuration */ | ||
235 | val &= ~WCNSS_PMU_GC_BUS_MUX_SEL_TOP; | ||
236 | val &= ~WCNSS_PMU_IRIS_XO_CFG; | ||
237 | writel(val, wcnss->pmu_cfg); | ||
238 | |||
239 | /* Add some delay for XO to settle */ | ||
240 | msleep(20); | ||
241 | } | ||
242 | |||
243 | static int wcnss_start(struct rproc *rproc) | ||
244 | { | ||
245 | struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; | ||
246 | int ret; | ||
247 | |||
248 | mutex_lock(&wcnss->iris_lock); | ||
249 | if (!wcnss->iris) { | ||
250 | dev_err(wcnss->dev, "no iris registered\n"); | ||
251 | ret = -EINVAL; | ||
252 | goto release_iris_lock; | ||
253 | } | ||
254 | |||
255 | ret = regulator_bulk_enable(wcnss->num_vregs, wcnss->vregs); | ||
256 | if (ret) | ||
257 | goto release_iris_lock; | ||
258 | |||
259 | ret = qcom_iris_enable(wcnss->iris); | ||
260 | if (ret) | ||
261 | goto disable_regulators; | ||
262 | |||
263 | wcnss_indicate_nv_download(wcnss); | ||
264 | wcnss_configure_iris(wcnss); | ||
265 | |||
266 | ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID); | ||
267 | if (ret) { | ||
268 | dev_err(wcnss->dev, | ||
269 | "failed to authenticate image and release reset\n"); | ||
270 | goto disable_iris; | ||
271 | } | ||
272 | |||
273 | ret = wait_for_completion_timeout(&wcnss->start_done, | ||
274 | msecs_to_jiffies(5000)); | ||
275 | if (wcnss->ready_irq > 0 && ret == 0) { | ||
276 | /* We have a ready_irq, but it didn't fire in time. */ | ||
277 | dev_err(wcnss->dev, "start timed out\n"); | ||
278 | qcom_scm_pas_shutdown(WCNSS_PAS_ID); | ||
279 | ret = -ETIMEDOUT; | ||
280 | goto disable_iris; | ||
281 | } | ||
282 | |||
283 | ret = 0; | ||
284 | |||
285 | disable_iris: | ||
286 | qcom_iris_disable(wcnss->iris); | ||
287 | disable_regulators: | ||
288 | regulator_bulk_disable(wcnss->num_vregs, wcnss->vregs); | ||
289 | release_iris_lock: | ||
290 | mutex_unlock(&wcnss->iris_lock); | ||
291 | |||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int wcnss_stop(struct rproc *rproc) | ||
296 | { | ||
297 | struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; | ||
298 | int ret; | ||
299 | |||
300 | if (wcnss->state) { | ||
301 | qcom_smem_state_update_bits(wcnss->state, | ||
302 | BIT(wcnss->stop_bit), | ||
303 | BIT(wcnss->stop_bit)); | ||
304 | |||
305 | ret = wait_for_completion_timeout(&wcnss->stop_done, | ||
306 | msecs_to_jiffies(5000)); | ||
307 | if (ret == 0) | ||
308 | dev_err(wcnss->dev, "timed out on wait\n"); | ||
309 | |||
310 | qcom_smem_state_update_bits(wcnss->state, | ||
311 | BIT(wcnss->stop_bit), | ||
312 | 0); | ||
313 | } | ||
314 | |||
315 | ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID); | ||
316 | if (ret) | ||
317 | dev_err(wcnss->dev, "failed to shutdown: %d\n", ret); | ||
318 | |||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len) | ||
323 | { | ||
324 | struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; | ||
325 | int offset; | ||
326 | |||
327 | offset = da - wcnss->mem_reloc; | ||
328 | if (offset < 0 || offset + len > wcnss->mem_size) | ||
329 | return NULL; | ||
330 | |||
331 | return wcnss->mem_region + offset; | ||
332 | } | ||
333 | |||
334 | static const struct rproc_ops wcnss_ops = { | ||
335 | .start = wcnss_start, | ||
336 | .stop = wcnss_stop, | ||
337 | .da_to_va = wcnss_da_to_va, | ||
338 | }; | ||
339 | |||
340 | static irqreturn_t wcnss_wdog_interrupt(int irq, void *dev) | ||
341 | { | ||
342 | struct qcom_wcnss *wcnss = dev; | ||
343 | |||
344 | rproc_report_crash(wcnss->rproc, RPROC_WATCHDOG); | ||
345 | |||
346 | return IRQ_HANDLED; | ||
347 | } | ||
348 | |||
349 | static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev) | ||
350 | { | ||
351 | struct qcom_wcnss *wcnss = dev; | ||
352 | size_t len; | ||
353 | char *msg; | ||
354 | |||
355 | msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, WCNSS_CRASH_REASON_SMEM, &len); | ||
356 | if (!IS_ERR(msg) && len > 0 && msg[0]) | ||
357 | dev_err(wcnss->dev, "fatal error received: %s\n", msg); | ||
358 | |||
359 | rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR); | ||
360 | |||
361 | if (!IS_ERR(msg)) | ||
362 | msg[0] = '\0'; | ||
363 | |||
364 | return IRQ_HANDLED; | ||
365 | } | ||
366 | |||
367 | static irqreturn_t wcnss_ready_interrupt(int irq, void *dev) | ||
368 | { | ||
369 | struct qcom_wcnss *wcnss = dev; | ||
370 | |||
371 | complete(&wcnss->start_done); | ||
372 | |||
373 | return IRQ_HANDLED; | ||
374 | } | ||
375 | |||
376 | static irqreturn_t wcnss_handover_interrupt(int irq, void *dev) | ||
377 | { | ||
378 | /* | ||
379 | * XXX: At this point we're supposed to release the resources that we | ||
380 | * have been holding on behalf of the WCNSS. Unfortunately this | ||
381 | * interrupt comes way before the other side seems to be done. | ||
382 | * | ||
383 | * So we're currently relying on the ready interrupt firing later then | ||
384 | * this and we just disable the resources at the end of wcnss_start(). | ||
385 | */ | ||
386 | |||
387 | return IRQ_HANDLED; | ||
388 | } | ||
389 | |||
390 | static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev) | ||
391 | { | ||
392 | struct qcom_wcnss *wcnss = dev; | ||
393 | |||
394 | complete(&wcnss->stop_done); | ||
395 | |||
396 | return IRQ_HANDLED; | ||
397 | } | ||
398 | |||
399 | static int wcnss_init_regulators(struct qcom_wcnss *wcnss, | ||
400 | const struct wcnss_vreg_info *info, | ||
401 | int num_vregs) | ||
402 | { | ||
403 | struct regulator_bulk_data *bulk; | ||
404 | int ret; | ||
405 | int i; | ||
406 | |||
407 | bulk = devm_kcalloc(wcnss->dev, | ||
408 | num_vregs, sizeof(struct regulator_bulk_data), | ||
409 | GFP_KERNEL); | ||
410 | if (!bulk) | ||
411 | return -ENOMEM; | ||
412 | |||
413 | for (i = 0; i < num_vregs; i++) | ||
414 | bulk[i].supply = info[i].name; | ||
415 | |||
416 | ret = devm_regulator_bulk_get(wcnss->dev, num_vregs, bulk); | ||
417 | if (ret) | ||
418 | return ret; | ||
419 | |||
420 | for (i = 0; i < num_vregs; i++) { | ||
421 | if (info[i].max_voltage) | ||
422 | regulator_set_voltage(bulk[i].consumer, | ||
423 | info[i].min_voltage, | ||
424 | info[i].max_voltage); | ||
425 | |||
426 | if (info[i].load_uA) | ||
427 | regulator_set_load(bulk[i].consumer, info[i].load_uA); | ||
428 | } | ||
429 | |||
430 | wcnss->vregs = bulk; | ||
431 | wcnss->num_vregs = num_vregs; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int wcnss_request_irq(struct qcom_wcnss *wcnss, | ||
437 | struct platform_device *pdev, | ||
438 | const char *name, | ||
439 | bool optional, | ||
440 | irq_handler_t thread_fn) | ||
441 | { | ||
442 | int ret; | ||
443 | |||
444 | ret = platform_get_irq_byname(pdev, name); | ||
445 | if (ret < 0 && optional) { | ||
446 | dev_dbg(&pdev->dev, "no %s IRQ defined, ignoring\n", name); | ||
447 | return 0; | ||
448 | } else if (ret < 0) { | ||
449 | dev_err(&pdev->dev, "no %s IRQ defined\n", name); | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | ret = devm_request_threaded_irq(&pdev->dev, ret, | ||
454 | NULL, thread_fn, | ||
455 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
456 | "wcnss", wcnss); | ||
457 | if (ret) | ||
458 | dev_err(&pdev->dev, "request %s IRQ failed\n", name); | ||
459 | |||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss) | ||
464 | { | ||
465 | struct device_node *node; | ||
466 | struct resource r; | ||
467 | int ret; | ||
468 | |||
469 | node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0); | ||
470 | if (!node) { | ||
471 | dev_err(wcnss->dev, "no memory-region specified\n"); | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | |||
475 | ret = of_address_to_resource(node, 0, &r); | ||
476 | if (ret) | ||
477 | return ret; | ||
478 | |||
479 | wcnss->mem_phys = wcnss->mem_reloc = r.start; | ||
480 | wcnss->mem_size = resource_size(&r); | ||
481 | wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size); | ||
482 | if (!wcnss->mem_region) { | ||
483 | dev_err(wcnss->dev, "unable to map memory region: %pa+%zx\n", | ||
484 | &r.start, wcnss->mem_size); | ||
485 | return -EBUSY; | ||
486 | } | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int wcnss_probe(struct platform_device *pdev) | ||
492 | { | ||
493 | const struct wcnss_data *data; | ||
494 | struct qcom_wcnss *wcnss; | ||
495 | struct resource *res; | ||
496 | struct rproc *rproc; | ||
497 | void __iomem *mmio; | ||
498 | int ret; | ||
499 | |||
500 | data = of_device_get_match_data(&pdev->dev); | ||
501 | |||
502 | if (!qcom_scm_is_available()) | ||
503 | return -EPROBE_DEFER; | ||
504 | |||
505 | if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) { | ||
506 | dev_err(&pdev->dev, "PAS is not available for WCNSS\n"); | ||
507 | return -ENXIO; | ||
508 | } | ||
509 | |||
510 | rproc = rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops, | ||
511 | WCNSS_FIRMWARE_NAME, sizeof(*wcnss)); | ||
512 | if (!rproc) { | ||
513 | dev_err(&pdev->dev, "unable to allocate remoteproc\n"); | ||
514 | return -ENOMEM; | ||
515 | } | ||
516 | |||
517 | rproc->fw_ops = &wcnss_fw_ops; | ||
518 | |||
519 | wcnss = (struct qcom_wcnss *)rproc->priv; | ||
520 | wcnss->dev = &pdev->dev; | ||
521 | wcnss->rproc = rproc; | ||
522 | platform_set_drvdata(pdev, wcnss); | ||
523 | |||
524 | init_completion(&wcnss->start_done); | ||
525 | init_completion(&wcnss->stop_done); | ||
526 | |||
527 | mutex_init(&wcnss->iris_lock); | ||
528 | |||
529 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu"); | ||
530 | mmio = devm_ioremap_resource(&pdev->dev, res); | ||
531 | if (IS_ERR(mmio)) { | ||
532 | ret = PTR_ERR(mmio); | ||
533 | goto free_rproc; | ||
534 | }; | ||
535 | |||
536 | ret = wcnss_alloc_memory_region(wcnss); | ||
537 | if (ret) | ||
538 | goto free_rproc; | ||
539 | |||
540 | wcnss->pmu_cfg = mmio + data->pmu_offset; | ||
541 | wcnss->spare_out = mmio + data->spare_offset; | ||
542 | |||
543 | ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs); | ||
544 | if (ret) | ||
545 | goto free_rproc; | ||
546 | |||
547 | ret = wcnss_request_irq(wcnss, pdev, "wdog", false, wcnss_wdog_interrupt); | ||
548 | if (ret < 0) | ||
549 | goto free_rproc; | ||
550 | wcnss->wdog_irq = ret; | ||
551 | |||
552 | ret = wcnss_request_irq(wcnss, pdev, "fatal", false, wcnss_fatal_interrupt); | ||
553 | if (ret < 0) | ||
554 | goto free_rproc; | ||
555 | wcnss->fatal_irq = ret; | ||
556 | |||
557 | ret = wcnss_request_irq(wcnss, pdev, "ready", true, wcnss_ready_interrupt); | ||
558 | if (ret < 0) | ||
559 | goto free_rproc; | ||
560 | wcnss->ready_irq = ret; | ||
561 | |||
562 | ret = wcnss_request_irq(wcnss, pdev, "handover", true, wcnss_handover_interrupt); | ||
563 | if (ret < 0) | ||
564 | goto free_rproc; | ||
565 | wcnss->handover_irq = ret; | ||
566 | |||
567 | ret = wcnss_request_irq(wcnss, pdev, "stop-ack", true, wcnss_stop_ack_interrupt); | ||
568 | if (ret < 0) | ||
569 | goto free_rproc; | ||
570 | wcnss->stop_ack_irq = ret; | ||
571 | |||
572 | if (wcnss->stop_ack_irq) { | ||
573 | wcnss->state = qcom_smem_state_get(&pdev->dev, "stop", | ||
574 | &wcnss->stop_bit); | ||
575 | if (IS_ERR(wcnss->state)) { | ||
576 | ret = PTR_ERR(wcnss->state); | ||
577 | goto free_rproc; | ||
578 | } | ||
579 | } | ||
580 | |||
581 | ret = rproc_add(rproc); | ||
582 | if (ret) | ||
583 | goto free_rproc; | ||
584 | |||
585 | return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); | ||
586 | |||
587 | free_rproc: | ||
588 | rproc_free(rproc); | ||
589 | |||
590 | return ret; | ||
591 | } | ||
592 | |||
593 | static int wcnss_remove(struct platform_device *pdev) | ||
594 | { | ||
595 | struct qcom_wcnss *wcnss = platform_get_drvdata(pdev); | ||
596 | |||
597 | of_platform_depopulate(&pdev->dev); | ||
598 | |||
599 | qcom_smem_state_put(wcnss->state); | ||
600 | rproc_del(wcnss->rproc); | ||
601 | rproc_free(wcnss->rproc); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static const struct of_device_id wcnss_of_match[] = { | ||
607 | { .compatible = "qcom,riva-pil", &riva_data }, | ||
608 | { .compatible = "qcom,pronto-v1-pil", &pronto_v1_data }, | ||
609 | { .compatible = "qcom,pronto-v2-pil", &pronto_v2_data }, | ||
610 | { }, | ||
611 | }; | ||
612 | |||
613 | static struct platform_driver wcnss_driver = { | ||
614 | .probe = wcnss_probe, | ||
615 | .remove = wcnss_remove, | ||
616 | .driver = { | ||
617 | .name = "qcom-wcnss-pil", | ||
618 | .of_match_table = wcnss_of_match, | ||
619 | }, | ||
620 | }; | ||
621 | |||
622 | module_platform_driver(wcnss_driver); | ||
623 | MODULE_DESCRIPTION("Qualcomm Peripherial Image Loader for Wireless Subsystem"); | ||
624 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/remoteproc/qcom_wcnss.h b/drivers/remoteproc/qcom_wcnss.h new file mode 100644 index 000000000000..9dc4a9fe41e1 --- /dev/null +++ b/drivers/remoteproc/qcom_wcnss.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef __QCOM_WNCSS_H__ | ||
2 | #define __QCOM_WNCSS_H__ | ||
3 | |||
4 | struct qcom_iris; | ||
5 | struct qcom_wcnss; | ||
6 | |||
7 | struct wcnss_vreg_info { | ||
8 | const char * const name; | ||
9 | int min_voltage; | ||
10 | int max_voltage; | ||
11 | |||
12 | int load_uA; | ||
13 | |||
14 | bool super_turbo; | ||
15 | }; | ||
16 | |||
17 | int qcom_iris_enable(struct qcom_iris *iris); | ||
18 | void qcom_iris_disable(struct qcom_iris *iris); | ||
19 | |||
20 | void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss, struct qcom_iris *iris, bool use_48mhz_xo); | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/remoteproc/qcom_wcnss_iris.c b/drivers/remoteproc/qcom_wcnss_iris.c new file mode 100644 index 000000000000..f0ca24a8dd0b --- /dev/null +++ b/drivers/remoteproc/qcom_wcnss_iris.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * Qualcomm Wireless Connectivity Subsystem Iris driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Linaro Ltd | ||
5 | * Copyright (C) 2014 Sony Mobile Communications AB | ||
6 | * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of_device.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | |||
25 | #include "qcom_wcnss.h" | ||
26 | |||
27 | struct qcom_iris { | ||
28 | struct device *dev; | ||
29 | |||
30 | struct clk *xo_clk; | ||
31 | |||
32 | struct regulator_bulk_data *vregs; | ||
33 | size_t num_vregs; | ||
34 | }; | ||
35 | |||
36 | struct iris_data { | ||
37 | const struct wcnss_vreg_info *vregs; | ||
38 | size_t num_vregs; | ||
39 | |||
40 | bool use_48mhz_xo; | ||
41 | }; | ||
42 | |||
43 | static const struct iris_data wcn3620_data = { | ||
44 | .vregs = (struct wcnss_vreg_info[]) { | ||
45 | { "vddxo", 1800000, 1800000, 10000 }, | ||
46 | { "vddrfa", 1300000, 1300000, 100000 }, | ||
47 | { "vddpa", 3300000, 3300000, 515000 }, | ||
48 | { "vdddig", 1800000, 1800000, 10000 }, | ||
49 | }, | ||
50 | .num_vregs = 4, | ||
51 | .use_48mhz_xo = false, | ||
52 | }; | ||
53 | |||
54 | static const struct iris_data wcn3660_data = { | ||
55 | .vregs = (struct wcnss_vreg_info[]) { | ||
56 | { "vddxo", 1800000, 1800000, 10000 }, | ||
57 | { "vddrfa", 1300000, 1300000, 100000 }, | ||
58 | { "vddpa", 2900000, 3000000, 515000 }, | ||
59 | { "vdddig", 1200000, 1225000, 10000 }, | ||
60 | }, | ||
61 | .num_vregs = 4, | ||
62 | .use_48mhz_xo = true, | ||
63 | }; | ||
64 | |||
65 | static const struct iris_data wcn3680_data = { | ||
66 | .vregs = (struct wcnss_vreg_info[]) { | ||
67 | { "vddxo", 1800000, 1800000, 10000 }, | ||
68 | { "vddrfa", 1300000, 1300000, 100000 }, | ||
69 | { "vddpa", 3300000, 3300000, 515000 }, | ||
70 | { "vdddig", 1800000, 1800000, 10000 }, | ||
71 | }, | ||
72 | .num_vregs = 4, | ||
73 | .use_48mhz_xo = true, | ||
74 | }; | ||
75 | |||
76 | int qcom_iris_enable(struct qcom_iris *iris) | ||
77 | { | ||
78 | int ret; | ||
79 | |||
80 | ret = regulator_bulk_enable(iris->num_vregs, iris->vregs); | ||
81 | if (ret) | ||
82 | return ret; | ||
83 | |||
84 | ret = clk_prepare_enable(iris->xo_clk); | ||
85 | if (ret) { | ||
86 | dev_err(iris->dev, "failed to enable xo clk\n"); | ||
87 | goto disable_regulators; | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | |||
92 | disable_regulators: | ||
93 | regulator_bulk_disable(iris->num_vregs, iris->vregs); | ||
94 | |||
95 | return ret; | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(qcom_iris_enable); | ||
98 | |||
99 | void qcom_iris_disable(struct qcom_iris *iris) | ||
100 | { | ||
101 | clk_disable_unprepare(iris->xo_clk); | ||
102 | regulator_bulk_disable(iris->num_vregs, iris->vregs); | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(qcom_iris_disable); | ||
105 | |||
106 | static int qcom_iris_probe(struct platform_device *pdev) | ||
107 | { | ||
108 | const struct iris_data *data; | ||
109 | struct qcom_wcnss *wcnss; | ||
110 | struct qcom_iris *iris; | ||
111 | int ret; | ||
112 | int i; | ||
113 | |||
114 | iris = devm_kzalloc(&pdev->dev, sizeof(struct qcom_iris), GFP_KERNEL); | ||
115 | if (!iris) | ||
116 | return -ENOMEM; | ||
117 | |||
118 | data = of_device_get_match_data(&pdev->dev); | ||
119 | wcnss = dev_get_drvdata(pdev->dev.parent); | ||
120 | |||
121 | iris->xo_clk = devm_clk_get(&pdev->dev, "xo"); | ||
122 | if (IS_ERR(iris->xo_clk)) { | ||
123 | if (PTR_ERR(iris->xo_clk) != -EPROBE_DEFER) | ||
124 | dev_err(&pdev->dev, "failed to acquire xo clk\n"); | ||
125 | return PTR_ERR(iris->xo_clk); | ||
126 | } | ||
127 | |||
128 | iris->num_vregs = data->num_vregs; | ||
129 | iris->vregs = devm_kcalloc(&pdev->dev, | ||
130 | iris->num_vregs, | ||
131 | sizeof(struct regulator_bulk_data), | ||
132 | GFP_KERNEL); | ||
133 | if (!iris->vregs) | ||
134 | return -ENOMEM; | ||
135 | |||
136 | for (i = 0; i < iris->num_vregs; i++) | ||
137 | iris->vregs[i].supply = data->vregs[i].name; | ||
138 | |||
139 | ret = devm_regulator_bulk_get(&pdev->dev, iris->num_vregs, iris->vregs); | ||
140 | if (ret) { | ||
141 | dev_err(&pdev->dev, "failed to get regulators\n"); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | for (i = 0; i < iris->num_vregs; i++) { | ||
146 | if (data->vregs[i].max_voltage) | ||
147 | regulator_set_voltage(iris->vregs[i].consumer, | ||
148 | data->vregs[i].min_voltage, | ||
149 | data->vregs[i].max_voltage); | ||
150 | |||
151 | if (data->vregs[i].load_uA) | ||
152 | regulator_set_load(iris->vregs[i].consumer, | ||
153 | data->vregs[i].load_uA); | ||
154 | } | ||
155 | |||
156 | qcom_wcnss_assign_iris(wcnss, iris, data->use_48mhz_xo); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int qcom_iris_remove(struct platform_device *pdev) | ||
162 | { | ||
163 | struct qcom_wcnss *wcnss = dev_get_drvdata(pdev->dev.parent); | ||
164 | |||
165 | qcom_wcnss_assign_iris(wcnss, NULL, false); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static const struct of_device_id iris_of_match[] = { | ||
171 | { .compatible = "qcom,wcn3620", .data = &wcn3620_data }, | ||
172 | { .compatible = "qcom,wcn3660", .data = &wcn3660_data }, | ||
173 | { .compatible = "qcom,wcn3680", .data = &wcn3680_data }, | ||
174 | {} | ||
175 | }; | ||
176 | |||
177 | static struct platform_driver wcnss_driver = { | ||
178 | .probe = qcom_iris_probe, | ||
179 | .remove = qcom_iris_remove, | ||
180 | .driver = { | ||
181 | .name = "qcom-iris", | ||
182 | .of_match_table = iris_of_match, | ||
183 | }, | ||
184 | }; | ||
185 | |||
186 | module_platform_driver(wcnss_driver); | ||
187 | MODULE_DESCRIPTION("Qualcomm Wireless Subsystem Iris driver"); | ||
188 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index fe0539ed9cb5..c6bfb3496684 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c | |||
@@ -78,7 +78,7 @@ static const char *rproc_crash_to_string(enum rproc_crash_type type) | |||
78 | * will try to access an unmapped device address. | 78 | * will try to access an unmapped device address. |
79 | */ | 79 | */ |
80 | static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, | 80 | static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, |
81 | unsigned long iova, int flags, void *token) | 81 | unsigned long iova, int flags, void *token) |
82 | { | 82 | { |
83 | struct rproc *rproc = token; | 83 | struct rproc *rproc = token; |
84 | 84 | ||
@@ -236,8 +236,8 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) | |||
236 | } | 236 | } |
237 | notifyid = ret; | 237 | notifyid = ret; |
238 | 238 | ||
239 | dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va, | 239 | dev_dbg(dev, "vring%d: va %p dma %pad size 0x%x idr %d\n", |
240 | (unsigned long long)dma, size, notifyid); | 240 | i, va, &dma, size, notifyid); |
241 | 241 | ||
242 | rvring->va = va; | 242 | rvring->va = va; |
243 | rvring->dma = dma; | 243 | rvring->dma = dma; |
@@ -263,19 +263,13 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i) | |||
263 | struct fw_rsc_vdev_vring *vring = &rsc->vring[i]; | 263 | struct fw_rsc_vdev_vring *vring = &rsc->vring[i]; |
264 | struct rproc_vring *rvring = &rvdev->vring[i]; | 264 | struct rproc_vring *rvring = &rvdev->vring[i]; |
265 | 265 | ||
266 | dev_dbg(dev, "vdev rsc: vring%d: da %x, qsz %d, align %d\n", | 266 | dev_dbg(dev, "vdev rsc: vring%d: da 0x%x, qsz %d, align %d\n", |
267 | i, vring->da, vring->num, vring->align); | 267 | i, vring->da, vring->num, vring->align); |
268 | |||
269 | /* make sure reserved bytes are zeroes */ | ||
270 | if (vring->reserved) { | ||
271 | dev_err(dev, "vring rsc has non zero reserved bytes\n"); | ||
272 | return -EINVAL; | ||
273 | } | ||
274 | 268 | ||
275 | /* verify queue size and vring alignment are sane */ | 269 | /* verify queue size and vring alignment are sane */ |
276 | if (!vring->num || !vring->align) { | 270 | if (!vring->num || !vring->align) { |
277 | dev_err(dev, "invalid qsz (%d) or alignment (%d)\n", | 271 | dev_err(dev, "invalid qsz (%d) or alignment (%d)\n", |
278 | vring->num, vring->align); | 272 | vring->num, vring->align); |
279 | return -EINVAL; | 273 | return -EINVAL; |
280 | } | 274 | } |
281 | 275 | ||
@@ -330,7 +324,7 @@ void rproc_free_vring(struct rproc_vring *rvring) | |||
330 | * Returns 0 on success, or an appropriate error code otherwise | 324 | * Returns 0 on success, or an appropriate error code otherwise |
331 | */ | 325 | */ |
332 | static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, | 326 | static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, |
333 | int offset, int avail) | 327 | int offset, int avail) |
334 | { | 328 | { |
335 | struct device *dev = &rproc->dev; | 329 | struct device *dev = &rproc->dev; |
336 | struct rproc_vdev *rvdev; | 330 | struct rproc_vdev *rvdev; |
@@ -349,7 +343,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, | |||
349 | return -EINVAL; | 343 | return -EINVAL; |
350 | } | 344 | } |
351 | 345 | ||
352 | dev_dbg(dev, "vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n", | 346 | dev_dbg(dev, "vdev rsc: id %d, dfeatures 0x%x, cfg len %d, %d vrings\n", |
353 | rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings); | 347 | rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings); |
354 | 348 | ||
355 | /* we currently support only two vrings per rvdev */ | 349 | /* we currently support only two vrings per rvdev */ |
@@ -358,7 +352,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, | |||
358 | return -EINVAL; | 352 | return -EINVAL; |
359 | } | 353 | } |
360 | 354 | ||
361 | rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL); | 355 | rvdev = kzalloc(sizeof(*rvdev), GFP_KERNEL); |
362 | if (!rvdev) | 356 | if (!rvdev) |
363 | return -ENOMEM; | 357 | return -ENOMEM; |
364 | 358 | ||
@@ -407,7 +401,7 @@ free_rvdev: | |||
407 | * Returns 0 on success, or an appropriate error code otherwise | 401 | * Returns 0 on success, or an appropriate error code otherwise |
408 | */ | 402 | */ |
409 | static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, | 403 | static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, |
410 | int offset, int avail) | 404 | int offset, int avail) |
411 | { | 405 | { |
412 | struct rproc_mem_entry *trace; | 406 | struct rproc_mem_entry *trace; |
413 | struct device *dev = &rproc->dev; | 407 | struct device *dev = &rproc->dev; |
@@ -455,8 +449,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, | |||
455 | 449 | ||
456 | rproc->num_traces++; | 450 | rproc->num_traces++; |
457 | 451 | ||
458 | dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n", name, ptr, | 452 | dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n", |
459 | rsc->da, rsc->len); | 453 | name, ptr, rsc->da, rsc->len); |
460 | 454 | ||
461 | return 0; | 455 | return 0; |
462 | } | 456 | } |
@@ -487,7 +481,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, | |||
487 | * are outside those ranges. | 481 | * are outside those ranges. |
488 | */ | 482 | */ |
489 | static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, | 483 | static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, |
490 | int offset, int avail) | 484 | int offset, int avail) |
491 | { | 485 | { |
492 | struct rproc_mem_entry *mapping; | 486 | struct rproc_mem_entry *mapping; |
493 | struct device *dev = &rproc->dev; | 487 | struct device *dev = &rproc->dev; |
@@ -530,7 +524,7 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, | |||
530 | list_add_tail(&mapping->node, &rproc->mappings); | 524 | list_add_tail(&mapping->node, &rproc->mappings); |
531 | 525 | ||
532 | dev_dbg(dev, "mapped devmem pa 0x%x, da 0x%x, len 0x%x\n", | 526 | dev_dbg(dev, "mapped devmem pa 0x%x, da 0x%x, len 0x%x\n", |
533 | rsc->pa, rsc->da, rsc->len); | 527 | rsc->pa, rsc->da, rsc->len); |
534 | 528 | ||
535 | return 0; | 529 | return 0; |
536 | 530 | ||
@@ -558,9 +552,8 @@ out: | |||
558 | * pressure is important; it may have a substantial impact on performance. | 552 | * pressure is important; it may have a substantial impact on performance. |
559 | */ | 553 | */ |
560 | static int rproc_handle_carveout(struct rproc *rproc, | 554 | static int rproc_handle_carveout(struct rproc *rproc, |
561 | struct fw_rsc_carveout *rsc, | 555 | struct fw_rsc_carveout *rsc, |
562 | int offset, int avail) | 556 | int offset, int avail) |
563 | |||
564 | { | 557 | { |
565 | struct rproc_mem_entry *carveout, *mapping; | 558 | struct rproc_mem_entry *carveout, *mapping; |
566 | struct device *dev = &rproc->dev; | 559 | struct device *dev = &rproc->dev; |
@@ -579,8 +572,8 @@ static int rproc_handle_carveout(struct rproc *rproc, | |||
579 | return -EINVAL; | 572 | return -EINVAL; |
580 | } | 573 | } |
581 | 574 | ||
582 | dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n", | 575 | dev_dbg(dev, "carveout rsc: name: %s, da 0x%x, pa 0x%x, len 0x%x, flags 0x%x\n", |
583 | rsc->da, rsc->pa, rsc->len, rsc->flags); | 576 | rsc->name, rsc->da, rsc->pa, rsc->len, rsc->flags); |
584 | 577 | ||
585 | carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); | 578 | carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); |
586 | if (!carveout) | 579 | if (!carveout) |
@@ -588,13 +581,14 @@ static int rproc_handle_carveout(struct rproc *rproc, | |||
588 | 581 | ||
589 | va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); | 582 | va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); |
590 | if (!va) { | 583 | if (!va) { |
591 | dev_err(dev->parent, "dma_alloc_coherent err: %d\n", rsc->len); | 584 | dev_err(dev->parent, |
585 | "failed to allocate dma memory: len 0x%x\n", rsc->len); | ||
592 | ret = -ENOMEM; | 586 | ret = -ENOMEM; |
593 | goto free_carv; | 587 | goto free_carv; |
594 | } | 588 | } |
595 | 589 | ||
596 | dev_dbg(dev, "carveout va %p, dma %llx, len 0x%x\n", va, | 590 | dev_dbg(dev, "carveout va %p, dma %pad, len 0x%x\n", |
597 | (unsigned long long)dma, rsc->len); | 591 | va, &dma, rsc->len); |
598 | 592 | ||
599 | /* | 593 | /* |
600 | * Ok, this is non-standard. | 594 | * Ok, this is non-standard. |
@@ -616,13 +610,12 @@ static int rproc_handle_carveout(struct rproc *rproc, | |||
616 | if (rproc->domain) { | 610 | if (rproc->domain) { |
617 | mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); | 611 | mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); |
618 | if (!mapping) { | 612 | if (!mapping) { |
619 | dev_err(dev, "kzalloc mapping failed\n"); | ||
620 | ret = -ENOMEM; | 613 | ret = -ENOMEM; |
621 | goto dma_free; | 614 | goto dma_free; |
622 | } | 615 | } |
623 | 616 | ||
624 | ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len, | 617 | ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len, |
625 | rsc->flags); | 618 | rsc->flags); |
626 | if (ret) { | 619 | if (ret) { |
627 | dev_err(dev, "iommu_map failed: %d\n", ret); | 620 | dev_err(dev, "iommu_map failed: %d\n", ret); |
628 | goto free_mapping; | 621 | goto free_mapping; |
@@ -639,8 +632,8 @@ static int rproc_handle_carveout(struct rproc *rproc, | |||
639 | mapping->len = rsc->len; | 632 | mapping->len = rsc->len; |
640 | list_add_tail(&mapping->node, &rproc->mappings); | 633 | list_add_tail(&mapping->node, &rproc->mappings); |
641 | 634 | ||
642 | dev_dbg(dev, "carveout mapped 0x%x to 0x%llx\n", | 635 | dev_dbg(dev, "carveout mapped 0x%x to %pad\n", |
643 | rsc->da, (unsigned long long)dma); | 636 | rsc->da, &dma); |
644 | } | 637 | } |
645 | 638 | ||
646 | /* | 639 | /* |
@@ -697,17 +690,13 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { | |||
697 | [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, | 690 | [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, |
698 | [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, | 691 | [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, |
699 | [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, | 692 | [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, |
700 | [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */ | 693 | [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings, |
701 | }; | 694 | }; |
702 | 695 | ||
703 | static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = { | 696 | static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = { |
704 | [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, | 697 | [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, |
705 | }; | 698 | }; |
706 | 699 | ||
707 | static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = { | ||
708 | [RSC_VDEV] = (rproc_handle_resource_t)rproc_count_vrings, | ||
709 | }; | ||
710 | |||
711 | /* handle firmware resource entries before booting the remote processor */ | 700 | /* handle firmware resource entries before booting the remote processor */ |
712 | static int rproc_handle_resources(struct rproc *rproc, int len, | 701 | static int rproc_handle_resources(struct rproc *rproc, int len, |
713 | rproc_handle_resource_t handlers[RSC_LAST]) | 702 | rproc_handle_resource_t handlers[RSC_LAST]) |
@@ -757,6 +746,7 @@ static int rproc_handle_resources(struct rproc *rproc, int len, | |||
757 | static void rproc_resource_cleanup(struct rproc *rproc) | 746 | static void rproc_resource_cleanup(struct rproc *rproc) |
758 | { | 747 | { |
759 | struct rproc_mem_entry *entry, *tmp; | 748 | struct rproc_mem_entry *entry, *tmp; |
749 | struct rproc_vdev *rvdev, *rvtmp; | ||
760 | struct device *dev = &rproc->dev; | 750 | struct device *dev = &rproc->dev; |
761 | 751 | ||
762 | /* clean up debugfs trace entries */ | 752 | /* clean up debugfs trace entries */ |
@@ -775,7 +765,7 @@ static void rproc_resource_cleanup(struct rproc *rproc) | |||
775 | if (unmapped != entry->len) { | 765 | if (unmapped != entry->len) { |
776 | /* nothing much to do besides complaining */ | 766 | /* nothing much to do besides complaining */ |
777 | dev_err(dev, "failed to unmap %u/%zu\n", entry->len, | 767 | dev_err(dev, "failed to unmap %u/%zu\n", entry->len, |
778 | unmapped); | 768 | unmapped); |
779 | } | 769 | } |
780 | 770 | ||
781 | list_del(&entry->node); | 771 | list_del(&entry->node); |
@@ -789,6 +779,10 @@ static void rproc_resource_cleanup(struct rproc *rproc) | |||
789 | list_del(&entry->node); | 779 | list_del(&entry->node); |
790 | kfree(entry); | 780 | kfree(entry); |
791 | } | 781 | } |
782 | |||
783 | /* clean up remote vdev entries */ | ||
784 | list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) | ||
785 | rproc_remove_virtio_dev(rvdev); | ||
792 | } | 786 | } |
793 | 787 | ||
794 | /* | 788 | /* |
@@ -801,9 +795,6 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) | |||
801 | struct resource_table *table, *loaded_table; | 795 | struct resource_table *table, *loaded_table; |
802 | int ret, tablesz; | 796 | int ret, tablesz; |
803 | 797 | ||
804 | if (!rproc->table_ptr) | ||
805 | return -ENOMEM; | ||
806 | |||
807 | ret = rproc_fw_sanity_check(rproc, fw); | 798 | ret = rproc_fw_sanity_check(rproc, fw); |
808 | if (ret) | 799 | if (ret) |
809 | return ret; | 800 | return ret; |
@@ -830,9 +821,25 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) | |||
830 | goto clean_up; | 821 | goto clean_up; |
831 | } | 822 | } |
832 | 823 | ||
833 | /* Verify that resource table in loaded fw is unchanged */ | 824 | /* |
834 | if (rproc->table_csum != crc32(0, table, tablesz)) { | 825 | * Create a copy of the resource table. When a virtio device starts |
835 | dev_err(dev, "resource checksum failed, fw changed?\n"); | 826 | * and calls vring_new_virtqueue() the address of the allocated vring |
827 | * will be stored in the cached_table. Before the device is started, | ||
828 | * cached_table will be copied into device memory. | ||
829 | */ | ||
830 | rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL); | ||
831 | if (!rproc->cached_table) | ||
832 | goto clean_up; | ||
833 | |||
834 | rproc->table_ptr = rproc->cached_table; | ||
835 | |||
836 | /* reset max_notifyid */ | ||
837 | rproc->max_notifyid = -1; | ||
838 | |||
839 | /* look for virtio devices and register them */ | ||
840 | ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler); | ||
841 | if (ret) { | ||
842 | dev_err(dev, "Failed to handle vdev resources: %d\n", ret); | ||
836 | goto clean_up; | 843 | goto clean_up; |
837 | } | 844 | } |
838 | 845 | ||
@@ -840,49 +847,50 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) | |||
840 | ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers); | 847 | ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers); |
841 | if (ret) { | 848 | if (ret) { |
842 | dev_err(dev, "Failed to process resources: %d\n", ret); | 849 | dev_err(dev, "Failed to process resources: %d\n", ret); |
843 | goto clean_up; | 850 | goto clean_up_resources; |
844 | } | 851 | } |
845 | 852 | ||
846 | /* load the ELF segments to memory */ | 853 | /* load the ELF segments to memory */ |
847 | ret = rproc_load_segments(rproc, fw); | 854 | ret = rproc_load_segments(rproc, fw); |
848 | if (ret) { | 855 | if (ret) { |
849 | dev_err(dev, "Failed to load program segments: %d\n", ret); | 856 | dev_err(dev, "Failed to load program segments: %d\n", ret); |
850 | goto clean_up; | 857 | goto clean_up_resources; |
851 | } | 858 | } |
852 | 859 | ||
853 | /* | 860 | /* |
854 | * The starting device has been given the rproc->cached_table as the | 861 | * The starting device has been given the rproc->cached_table as the |
855 | * resource table. The address of the vring along with the other | 862 | * resource table. The address of the vring along with the other |
856 | * allocated resources (carveouts etc) is stored in cached_table. | 863 | * allocated resources (carveouts etc) is stored in cached_table. |
857 | * In order to pass this information to the remote device we must | 864 | * In order to pass this information to the remote device we must copy |
858 | * copy this information to device memory. | 865 | * this information to device memory. We also update the table_ptr so |
866 | * that any subsequent changes will be applied to the loaded version. | ||
859 | */ | 867 | */ |
860 | loaded_table = rproc_find_loaded_rsc_table(rproc, fw); | 868 | loaded_table = rproc_find_loaded_rsc_table(rproc, fw); |
861 | if (loaded_table) | 869 | if (loaded_table) { |
862 | memcpy(loaded_table, rproc->cached_table, tablesz); | 870 | memcpy(loaded_table, rproc->cached_table, tablesz); |
871 | rproc->table_ptr = loaded_table; | ||
872 | } | ||
863 | 873 | ||
864 | /* power up the remote processor */ | 874 | /* power up the remote processor */ |
865 | ret = rproc->ops->start(rproc); | 875 | ret = rproc->ops->start(rproc); |
866 | if (ret) { | 876 | if (ret) { |
867 | dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret); | 877 | dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret); |
868 | goto clean_up; | 878 | goto clean_up_resources; |
869 | } | 879 | } |
870 | 880 | ||
871 | /* | ||
872 | * Update table_ptr so that all subsequent vring allocations and | ||
873 | * virtio fields manipulation update the actual loaded resource table | ||
874 | * in device memory. | ||
875 | */ | ||
876 | rproc->table_ptr = loaded_table; | ||
877 | |||
878 | rproc->state = RPROC_RUNNING; | 881 | rproc->state = RPROC_RUNNING; |
879 | 882 | ||
880 | dev_info(dev, "remote processor %s is now up\n", rproc->name); | 883 | dev_info(dev, "remote processor %s is now up\n", rproc->name); |
881 | 884 | ||
882 | return 0; | 885 | return 0; |
883 | 886 | ||
884 | clean_up: | 887 | clean_up_resources: |
885 | rproc_resource_cleanup(rproc); | 888 | rproc_resource_cleanup(rproc); |
889 | clean_up: | ||
890 | kfree(rproc->cached_table); | ||
891 | rproc->cached_table = NULL; | ||
892 | rproc->table_ptr = NULL; | ||
893 | |||
886 | rproc_disable_iommu(rproc); | 894 | rproc_disable_iommu(rproc); |
887 | return ret; | 895 | return ret; |
888 | } | 896 | } |
@@ -898,42 +906,11 @@ clean_up: | |||
898 | static void rproc_fw_config_virtio(const struct firmware *fw, void *context) | 906 | static void rproc_fw_config_virtio(const struct firmware *fw, void *context) |
899 | { | 907 | { |
900 | struct rproc *rproc = context; | 908 | struct rproc *rproc = context; |
901 | struct resource_table *table; | ||
902 | int ret, tablesz; | ||
903 | |||
904 | if (rproc_fw_sanity_check(rproc, fw) < 0) | ||
905 | goto out; | ||
906 | |||
907 | /* look for the resource table */ | ||
908 | table = rproc_find_rsc_table(rproc, fw, &tablesz); | ||
909 | if (!table) | ||
910 | goto out; | ||
911 | |||
912 | rproc->table_csum = crc32(0, table, tablesz); | ||
913 | |||
914 | /* | ||
915 | * Create a copy of the resource table. When a virtio device starts | ||
916 | * and calls vring_new_virtqueue() the address of the allocated vring | ||
917 | * will be stored in the cached_table. Before the device is started, | ||
918 | * cached_table will be copied into devic memory. | ||
919 | */ | ||
920 | rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL); | ||
921 | if (!rproc->cached_table) | ||
922 | goto out; | ||
923 | |||
924 | rproc->table_ptr = rproc->cached_table; | ||
925 | 909 | ||
926 | /* count the number of notify-ids */ | 910 | /* if rproc is marked always-on, request it to boot */ |
927 | rproc->max_notifyid = -1; | 911 | if (rproc->auto_boot) |
928 | ret = rproc_handle_resources(rproc, tablesz, | 912 | rproc_boot_nowait(rproc); |
929 | rproc_count_vrings_handler); | ||
930 | if (ret) | ||
931 | goto out; | ||
932 | |||
933 | /* look for virtio devices and register them */ | ||
934 | ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler); | ||
935 | 913 | ||
936 | out: | ||
937 | release_firmware(fw); | 914 | release_firmware(fw); |
938 | /* allow rproc_del() contexts, if any, to proceed */ | 915 | /* allow rproc_del() contexts, if any, to proceed */ |
939 | complete_all(&rproc->firmware_loading_complete); | 916 | complete_all(&rproc->firmware_loading_complete); |
@@ -969,7 +946,7 @@ static int rproc_add_virtio_devices(struct rproc *rproc) | |||
969 | * rproc_trigger_recovery() - recover a remoteproc | 946 | * rproc_trigger_recovery() - recover a remoteproc |
970 | * @rproc: the remote processor | 947 | * @rproc: the remote processor |
971 | * | 948 | * |
972 | * The recovery is done by reseting all the virtio devices, that way all the | 949 | * The recovery is done by resetting all the virtio devices, that way all the |
973 | * rpmsg drivers will be reseted along with the remote processor making the | 950 | * rpmsg drivers will be reseted along with the remote processor making the |
974 | * remoteproc functional again. | 951 | * remoteproc functional again. |
975 | * | 952 | * |
@@ -977,23 +954,23 @@ static int rproc_add_virtio_devices(struct rproc *rproc) | |||
977 | */ | 954 | */ |
978 | int rproc_trigger_recovery(struct rproc *rproc) | 955 | int rproc_trigger_recovery(struct rproc *rproc) |
979 | { | 956 | { |
980 | struct rproc_vdev *rvdev, *rvtmp; | ||
981 | |||
982 | dev_err(&rproc->dev, "recovering %s\n", rproc->name); | 957 | dev_err(&rproc->dev, "recovering %s\n", rproc->name); |
983 | 958 | ||
984 | init_completion(&rproc->crash_comp); | 959 | init_completion(&rproc->crash_comp); |
985 | 960 | ||
986 | /* clean up remote vdev entries */ | 961 | /* shut down the remote */ |
987 | list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) | 962 | /* TODO: make sure this works with rproc->power > 1 */ |
988 | rproc_remove_virtio_dev(rvdev); | 963 | rproc_shutdown(rproc); |
989 | 964 | ||
990 | /* wait until there is no more rproc users */ | 965 | /* wait until there is no more rproc users */ |
991 | wait_for_completion(&rproc->crash_comp); | 966 | wait_for_completion(&rproc->crash_comp); |
992 | 967 | ||
993 | /* Free the copy of the resource table */ | 968 | /* |
994 | kfree(rproc->cached_table); | 969 | * boot the remote processor up again |
970 | */ | ||
971 | rproc_boot(rproc); | ||
995 | 972 | ||
996 | return rproc_add_virtio_devices(rproc); | 973 | return 0; |
997 | } | 974 | } |
998 | 975 | ||
999 | /** | 976 | /** |
@@ -1058,20 +1035,6 @@ static int __rproc_boot(struct rproc *rproc, bool wait) | |||
1058 | return ret; | 1035 | return ret; |
1059 | } | 1036 | } |
1060 | 1037 | ||
1061 | /* loading a firmware is required */ | ||
1062 | if (!rproc->firmware) { | ||
1063 | dev_err(dev, "%s: no firmware to load\n", __func__); | ||
1064 | ret = -EINVAL; | ||
1065 | goto unlock_mutex; | ||
1066 | } | ||
1067 | |||
1068 | /* prevent underlying implementation from being removed */ | ||
1069 | if (!try_module_get(dev->parent->driver->owner)) { | ||
1070 | dev_err(dev, "%s: can't get owner\n", __func__); | ||
1071 | ret = -EINVAL; | ||
1072 | goto unlock_mutex; | ||
1073 | } | ||
1074 | |||
1075 | /* skip the boot process if rproc is already powered up */ | 1038 | /* skip the boot process if rproc is already powered up */ |
1076 | if (atomic_inc_return(&rproc->power) > 1) { | 1039 | if (atomic_inc_return(&rproc->power) > 1) { |
1077 | ret = 0; | 1040 | ret = 0; |
@@ -1096,10 +1059,8 @@ static int __rproc_boot(struct rproc *rproc, bool wait) | |||
1096 | release_firmware(firmware_p); | 1059 | release_firmware(firmware_p); |
1097 | 1060 | ||
1098 | downref_rproc: | 1061 | downref_rproc: |
1099 | if (ret) { | 1062 | if (ret) |
1100 | module_put(dev->parent->driver->owner); | ||
1101 | atomic_dec(&rproc->power); | 1063 | atomic_dec(&rproc->power); |
1102 | } | ||
1103 | unlock_mutex: | 1064 | unlock_mutex: |
1104 | mutex_unlock(&rproc->lock); | 1065 | mutex_unlock(&rproc->lock); |
1105 | return ret; | 1066 | return ret; |
@@ -1173,8 +1134,10 @@ void rproc_shutdown(struct rproc *rproc) | |||
1173 | 1134 | ||
1174 | rproc_disable_iommu(rproc); | 1135 | rproc_disable_iommu(rproc); |
1175 | 1136 | ||
1176 | /* Give the next start a clean resource table */ | 1137 | /* Free the copy of the resource table */ |
1177 | rproc->table_ptr = rproc->cached_table; | 1138 | kfree(rproc->cached_table); |
1139 | rproc->cached_table = NULL; | ||
1140 | rproc->table_ptr = NULL; | ||
1178 | 1141 | ||
1179 | /* if in crash state, unlock crash handler */ | 1142 | /* if in crash state, unlock crash handler */ |
1180 | if (rproc->state == RPROC_CRASHED) | 1143 | if (rproc->state == RPROC_CRASHED) |
@@ -1186,8 +1149,6 @@ void rproc_shutdown(struct rproc *rproc) | |||
1186 | 1149 | ||
1187 | out: | 1150 | out: |
1188 | mutex_unlock(&rproc->lock); | 1151 | mutex_unlock(&rproc->lock); |
1189 | if (!ret) | ||
1190 | module_put(dev->parent->driver->owner); | ||
1191 | } | 1152 | } |
1192 | EXPORT_SYMBOL(rproc_shutdown); | 1153 | EXPORT_SYMBOL(rproc_shutdown); |
1193 | 1154 | ||
@@ -1216,6 +1177,12 @@ struct rproc *rproc_get_by_phandle(phandle phandle) | |||
1216 | mutex_lock(&rproc_list_mutex); | 1177 | mutex_lock(&rproc_list_mutex); |
1217 | list_for_each_entry(r, &rproc_list, node) { | 1178 | list_for_each_entry(r, &rproc_list, node) { |
1218 | if (r->dev.parent && r->dev.parent->of_node == np) { | 1179 | if (r->dev.parent && r->dev.parent->of_node == np) { |
1180 | /* prevent underlying implementation from being removed */ | ||
1181 | if (!try_module_get(r->dev.parent->driver->owner)) { | ||
1182 | dev_err(&r->dev, "can't get owner\n"); | ||
1183 | break; | ||
1184 | } | ||
1185 | |||
1219 | rproc = r; | 1186 | rproc = r; |
1220 | get_device(&rproc->dev); | 1187 | get_device(&rproc->dev); |
1221 | break; | 1188 | break; |
@@ -1335,11 +1302,11 @@ static struct device_type rproc_type = { | |||
1335 | * On success the new rproc is returned, and on failure, NULL. | 1302 | * On success the new rproc is returned, and on failure, NULL. |
1336 | * | 1303 | * |
1337 | * Note: _never_ directly deallocate @rproc, even if it was not registered | 1304 | * Note: _never_ directly deallocate @rproc, even if it was not registered |
1338 | * yet. Instead, when you need to unroll rproc_alloc(), use rproc_put(). | 1305 | * yet. Instead, when you need to unroll rproc_alloc(), use rproc_free(). |
1339 | */ | 1306 | */ |
1340 | struct rproc *rproc_alloc(struct device *dev, const char *name, | 1307 | struct rproc *rproc_alloc(struct device *dev, const char *name, |
1341 | const struct rproc_ops *ops, | 1308 | const struct rproc_ops *ops, |
1342 | const char *firmware, int len) | 1309 | const char *firmware, int len) |
1343 | { | 1310 | { |
1344 | struct rproc *rproc; | 1311 | struct rproc *rproc; |
1345 | char *p, *template = "rproc-%s-fw"; | 1312 | char *p, *template = "rproc-%s-fw"; |
@@ -1359,7 +1326,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, | |||
1359 | */ | 1326 | */ |
1360 | name_len = strlen(name) + strlen(template) - 2 + 1; | 1327 | name_len = strlen(name) + strlen(template) - 2 + 1; |
1361 | 1328 | ||
1362 | rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL); | 1329 | rproc = kzalloc(sizeof(*rproc) + len + name_len, GFP_KERNEL); |
1363 | if (!rproc) | 1330 | if (!rproc) |
1364 | return NULL; | 1331 | return NULL; |
1365 | 1332 | ||
@@ -1374,6 +1341,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, | |||
1374 | rproc->name = name; | 1341 | rproc->name = name; |
1375 | rproc->ops = ops; | 1342 | rproc->ops = ops; |
1376 | rproc->priv = &rproc[1]; | 1343 | rproc->priv = &rproc[1]; |
1344 | rproc->auto_boot = true; | ||
1377 | 1345 | ||
1378 | device_initialize(&rproc->dev); | 1346 | device_initialize(&rproc->dev); |
1379 | rproc->dev.parent = dev; | 1347 | rproc->dev.parent = dev; |
@@ -1413,7 +1381,22 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, | |||
1413 | EXPORT_SYMBOL(rproc_alloc); | 1381 | EXPORT_SYMBOL(rproc_alloc); |
1414 | 1382 | ||
1415 | /** | 1383 | /** |
1416 | * rproc_put() - unroll rproc_alloc() | 1384 | * rproc_free() - unroll rproc_alloc() |
1385 | * @rproc: the remote processor handle | ||
1386 | * | ||
1387 | * This function decrements the rproc dev refcount. | ||
1388 | * | ||
1389 | * If no one holds any reference to rproc anymore, then its refcount would | ||
1390 | * now drop to zero, and it would be freed. | ||
1391 | */ | ||
1392 | void rproc_free(struct rproc *rproc) | ||
1393 | { | ||
1394 | put_device(&rproc->dev); | ||
1395 | } | ||
1396 | EXPORT_SYMBOL(rproc_free); | ||
1397 | |||
1398 | /** | ||
1399 | * rproc_put() - release rproc reference | ||
1417 | * @rproc: the remote processor handle | 1400 | * @rproc: the remote processor handle |
1418 | * | 1401 | * |
1419 | * This function decrements the rproc dev refcount. | 1402 | * This function decrements the rproc dev refcount. |
@@ -1423,6 +1406,7 @@ EXPORT_SYMBOL(rproc_alloc); | |||
1423 | */ | 1406 | */ |
1424 | void rproc_put(struct rproc *rproc) | 1407 | void rproc_put(struct rproc *rproc) |
1425 | { | 1408 | { |
1409 | module_put(rproc->dev.parent->driver->owner); | ||
1426 | put_device(&rproc->dev); | 1410 | put_device(&rproc->dev); |
1427 | } | 1411 | } |
1428 | EXPORT_SYMBOL(rproc_put); | 1412 | EXPORT_SYMBOL(rproc_put); |
@@ -1438,7 +1422,7 @@ EXPORT_SYMBOL(rproc_put); | |||
1438 | * | 1422 | * |
1439 | * After rproc_del() returns, @rproc isn't freed yet, because | 1423 | * After rproc_del() returns, @rproc isn't freed yet, because |
1440 | * of the outstanding reference created by rproc_alloc. To decrement that | 1424 | * of the outstanding reference created by rproc_alloc. To decrement that |
1441 | * one last refcount, one still needs to call rproc_put(). | 1425 | * one last refcount, one still needs to call rproc_free(). |
1442 | * | 1426 | * |
1443 | * Returns 0 on success and -EINVAL if @rproc isn't valid. | 1427 | * Returns 0 on success and -EINVAL if @rproc isn't valid. |
1444 | */ | 1428 | */ |
@@ -1452,13 +1436,15 @@ int rproc_del(struct rproc *rproc) | |||
1452 | /* if rproc is just being registered, wait */ | 1436 | /* if rproc is just being registered, wait */ |
1453 | wait_for_completion(&rproc->firmware_loading_complete); | 1437 | wait_for_completion(&rproc->firmware_loading_complete); |
1454 | 1438 | ||
1439 | /* if rproc is marked always-on, rproc_add() booted it */ | ||
1440 | /* TODO: make sure this works with rproc->power > 1 */ | ||
1441 | if (rproc->auto_boot) | ||
1442 | rproc_shutdown(rproc); | ||
1443 | |||
1455 | /* clean up remote vdev entries */ | 1444 | /* clean up remote vdev entries */ |
1456 | list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node) | 1445 | list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node) |
1457 | rproc_remove_virtio_dev(rvdev); | 1446 | rproc_remove_virtio_dev(rvdev); |
1458 | 1447 | ||
1459 | /* Free the copy of the resource table */ | ||
1460 | kfree(rproc->cached_table); | ||
1461 | |||
1462 | /* the rproc is downref'ed as soon as it's removed from the klist */ | 1448 | /* the rproc is downref'ed as soon as it's removed from the klist */ |
1463 | mutex_lock(&rproc_list_mutex); | 1449 | mutex_lock(&rproc_list_mutex); |
1464 | list_del(&rproc->node); | 1450 | list_del(&rproc->node); |
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 74a120b6e206..374797206c79 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c | |||
@@ -45,7 +45,7 @@ static struct dentry *rproc_dbg; | |||
45 | * as it provides very early tracing with little to no dependencies at all. | 45 | * as it provides very early tracing with little to no dependencies at all. |
46 | */ | 46 | */ |
47 | static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, | 47 | static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, |
48 | size_t count, loff_t *ppos) | 48 | size_t count, loff_t *ppos) |
49 | { | 49 | { |
50 | struct rproc_mem_entry *trace = filp->private_data; | 50 | struct rproc_mem_entry *trace = filp->private_data; |
51 | int len = strnlen(trace->va, trace->len); | 51 | int len = strnlen(trace->va, trace->len); |
@@ -73,7 +73,7 @@ static const char * const rproc_state_string[] = { | |||
73 | 73 | ||
74 | /* expose the state of the remote processor via debugfs */ | 74 | /* expose the state of the remote processor via debugfs */ |
75 | static ssize_t rproc_state_read(struct file *filp, char __user *userbuf, | 75 | static ssize_t rproc_state_read(struct file *filp, char __user *userbuf, |
76 | size_t count, loff_t *ppos) | 76 | size_t count, loff_t *ppos) |
77 | { | 77 | { |
78 | struct rproc *rproc = filp->private_data; | 78 | struct rproc *rproc = filp->private_data; |
79 | unsigned int state; | 79 | unsigned int state; |
@@ -83,7 +83,7 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf, | |||
83 | state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state; | 83 | state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state; |
84 | 84 | ||
85 | i = scnprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state], | 85 | i = scnprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state], |
86 | rproc->state); | 86 | rproc->state); |
87 | 87 | ||
88 | return simple_read_from_buffer(userbuf, count, ppos, buf, i); | 88 | return simple_read_from_buffer(userbuf, count, ppos, buf, i); |
89 | } | 89 | } |
@@ -130,7 +130,7 @@ static const struct file_operations rproc_state_ops = { | |||
130 | 130 | ||
131 | /* expose the name of the remote processor via debugfs */ | 131 | /* expose the name of the remote processor via debugfs */ |
132 | static ssize_t rproc_name_read(struct file *filp, char __user *userbuf, | 132 | static ssize_t rproc_name_read(struct file *filp, char __user *userbuf, |
133 | size_t count, loff_t *ppos) | 133 | size_t count, loff_t *ppos) |
134 | { | 134 | { |
135 | struct rproc *rproc = filp->private_data; | 135 | struct rproc *rproc = filp->private_data; |
136 | /* need room for the name, a newline and a terminating null */ | 136 | /* need room for the name, a newline and a terminating null */ |
@@ -230,12 +230,12 @@ void rproc_remove_trace_file(struct dentry *tfile) | |||
230 | } | 230 | } |
231 | 231 | ||
232 | struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, | 232 | struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, |
233 | struct rproc_mem_entry *trace) | 233 | struct rproc_mem_entry *trace) |
234 | { | 234 | { |
235 | struct dentry *tfile; | 235 | struct dentry *tfile; |
236 | 236 | ||
237 | tfile = debugfs_create_file(name, 0400, rproc->dbg_dir, | 237 | tfile = debugfs_create_file(name, 0400, rproc->dbg_dir, trace, |
238 | trace, &trace_rproc_ops); | 238 | &trace_rproc_ops); |
239 | if (!tfile) { | 239 | if (!tfile) { |
240 | dev_err(&rproc->dev, "failed to create debugfs trace entry\n"); | 240 | dev_err(&rproc->dev, "failed to create debugfs trace entry\n"); |
241 | return NULL; | 241 | return NULL; |
@@ -264,11 +264,11 @@ void rproc_create_debug_dir(struct rproc *rproc) | |||
264 | return; | 264 | return; |
265 | 265 | ||
266 | debugfs_create_file("name", 0400, rproc->dbg_dir, | 266 | debugfs_create_file("name", 0400, rproc->dbg_dir, |
267 | rproc, &rproc_name_ops); | 267 | rproc, &rproc_name_ops); |
268 | debugfs_create_file("state", 0400, rproc->dbg_dir, | 268 | debugfs_create_file("state", 0400, rproc->dbg_dir, |
269 | rproc, &rproc_state_ops); | 269 | rproc, &rproc_state_ops); |
270 | debugfs_create_file("recovery", 0400, rproc->dbg_dir, | 270 | debugfs_create_file("recovery", 0400, rproc->dbg_dir, |
271 | rproc, &rproc_recovery_ops); | 271 | rproc, &rproc_recovery_ops); |
272 | } | 272 | } |
273 | 273 | ||
274 | void __init rproc_init_debugfs(void) | 274 | void __init rproc_init_debugfs(void) |
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index ce283a5b42a1..c523983a4aec 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c | |||
@@ -166,18 +166,18 @@ rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) | |||
166 | continue; | 166 | continue; |
167 | 167 | ||
168 | dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", | 168 | dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", |
169 | phdr->p_type, da, memsz, filesz); | 169 | phdr->p_type, da, memsz, filesz); |
170 | 170 | ||
171 | if (filesz > memsz) { | 171 | if (filesz > memsz) { |
172 | dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", | 172 | dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", |
173 | filesz, memsz); | 173 | filesz, memsz); |
174 | ret = -EINVAL; | 174 | ret = -EINVAL; |
175 | break; | 175 | break; |
176 | } | 176 | } |
177 | 177 | ||
178 | if (offset + filesz > fw->size) { | 178 | if (offset + filesz > fw->size) { |
179 | dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", | 179 | dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", |
180 | offset + filesz, fw->size); | 180 | offset + filesz, fw->size); |
181 | ret = -EINVAL; | 181 | ret = -EINVAL; |
182 | break; | 182 | break; |
183 | } | 183 | } |
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index 57e1de59bec8..4cf93ca2816e 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h | |||
@@ -36,10 +36,10 @@ struct rproc; | |||
36 | */ | 36 | */ |
37 | struct rproc_fw_ops { | 37 | struct rproc_fw_ops { |
38 | struct resource_table *(*find_rsc_table)(struct rproc *rproc, | 38 | struct resource_table *(*find_rsc_table)(struct rproc *rproc, |
39 | const struct firmware *fw, | 39 | const struct firmware *fw, |
40 | int *tablesz); | 40 | int *tablesz); |
41 | struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc, | 41 | struct resource_table *(*find_loaded_rsc_table)( |
42 | const struct firmware *fw); | 42 | struct rproc *rproc, const struct firmware *fw); |
43 | int (*load)(struct rproc *rproc, const struct firmware *fw); | 43 | int (*load)(struct rproc *rproc, const struct firmware *fw); |
44 | int (*sanity_check)(struct rproc *rproc, const struct firmware *fw); | 44 | int (*sanity_check)(struct rproc *rproc, const struct firmware *fw); |
45 | u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); | 45 | u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); |
@@ -57,7 +57,7 @@ void rproc_remove_virtio_dev(struct rproc_vdev *rvdev); | |||
57 | /* from remoteproc_debugfs.c */ | 57 | /* from remoteproc_debugfs.c */ |
58 | void rproc_remove_trace_file(struct dentry *tfile); | 58 | void rproc_remove_trace_file(struct dentry *tfile); |
59 | struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, | 59 | struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, |
60 | struct rproc_mem_entry *trace); | 60 | struct rproc_mem_entry *trace); |
61 | void rproc_delete_debug_dir(struct rproc *rproc); | 61 | void rproc_delete_debug_dir(struct rproc *rproc); |
62 | void rproc_create_debug_dir(struct rproc *rproc); | 62 | void rproc_create_debug_dir(struct rproc *rproc); |
63 | void rproc_init_debugfs(void); | 63 | void rproc_init_debugfs(void); |
@@ -98,7 +98,8 @@ int rproc_load_segments(struct rproc *rproc, const struct firmware *fw) | |||
98 | 98 | ||
99 | static inline | 99 | static inline |
100 | struct resource_table *rproc_find_rsc_table(struct rproc *rproc, | 100 | struct resource_table *rproc_find_rsc_table(struct rproc *rproc, |
101 | const struct firmware *fw, int *tablesz) | 101 | const struct firmware *fw, |
102 | int *tablesz) | ||
102 | { | 103 | { |
103 | if (rproc->fw_ops->find_rsc_table) | 104 | if (rproc->fw_ops->find_rsc_table) |
104 | return rproc->fw_ops->find_rsc_table(rproc, fw, tablesz); | 105 | return rproc->fw_ops->find_rsc_table(rproc, fw, tablesz); |
@@ -108,7 +109,7 @@ struct resource_table *rproc_find_rsc_table(struct rproc *rproc, | |||
108 | 109 | ||
109 | static inline | 110 | static inline |
110 | struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc, | 111 | struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc, |
111 | const struct firmware *fw) | 112 | const struct firmware *fw) |
112 | { | 113 | { |
113 | if (rproc->fw_ops->find_loaded_rsc_table) | 114 | if (rproc->fw_ops->find_loaded_rsc_table) |
114 | return rproc->fw_ops->find_loaded_rsc_table(rproc, fw); | 115 | return rproc->fw_ops->find_loaded_rsc_table(rproc, fw); |
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index cc91556313e1..01870a16d6d2 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c | |||
@@ -69,7 +69,7 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) | |||
69 | EXPORT_SYMBOL(rproc_vq_interrupt); | 69 | EXPORT_SYMBOL(rproc_vq_interrupt); |
70 | 70 | ||
71 | static struct virtqueue *rp_find_vq(struct virtio_device *vdev, | 71 | static struct virtqueue *rp_find_vq(struct virtio_device *vdev, |
72 | unsigned id, | 72 | unsigned int id, |
73 | void (*callback)(struct virtqueue *vq), | 73 | void (*callback)(struct virtqueue *vq), |
74 | const char *name) | 74 | const char *name) |
75 | { | 75 | { |
@@ -101,14 +101,14 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, | |||
101 | memset(addr, 0, size); | 101 | memset(addr, 0, size); |
102 | 102 | ||
103 | dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n", | 103 | dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n", |
104 | id, addr, len, rvring->notifyid); | 104 | id, addr, len, rvring->notifyid); |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * Create the new vq, and tell virtio we're not interested in | 107 | * Create the new vq, and tell virtio we're not interested in |
108 | * the 'weak' smp barriers, since we're talking with a real device. | 108 | * the 'weak' smp barriers, since we're talking with a real device. |
109 | */ | 109 | */ |
110 | vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, addr, | 110 | vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, addr, |
111 | rproc_virtio_notify, callback, name); | 111 | rproc_virtio_notify, callback, name); |
112 | if (!vq) { | 112 | if (!vq) { |
113 | dev_err(dev, "vring_new_virtqueue %s failed\n", name); | 113 | dev_err(dev, "vring_new_virtqueue %s failed\n", name); |
114 | rproc_free_vring(rvring); | 114 | rproc_free_vring(rvring); |
@@ -136,20 +136,14 @@ static void __rproc_virtio_del_vqs(struct virtio_device *vdev) | |||
136 | 136 | ||
137 | static void rproc_virtio_del_vqs(struct virtio_device *vdev) | 137 | static void rproc_virtio_del_vqs(struct virtio_device *vdev) |
138 | { | 138 | { |
139 | struct rproc *rproc = vdev_to_rproc(vdev); | ||
140 | |||
141 | /* power down the remote processor before deleting vqs */ | ||
142 | rproc_shutdown(rproc); | ||
143 | |||
144 | __rproc_virtio_del_vqs(vdev); | 139 | __rproc_virtio_del_vqs(vdev); |
145 | } | 140 | } |
146 | 141 | ||
147 | static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, | 142 | static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, |
148 | struct virtqueue *vqs[], | 143 | struct virtqueue *vqs[], |
149 | vq_callback_t *callbacks[], | 144 | vq_callback_t *callbacks[], |
150 | const char * const names[]) | 145 | const char * const names[]) |
151 | { | 146 | { |
152 | struct rproc *rproc = vdev_to_rproc(vdev); | ||
153 | int i, ret; | 147 | int i, ret; |
154 | 148 | ||
155 | for (i = 0; i < nvqs; ++i) { | 149 | for (i = 0; i < nvqs; ++i) { |
@@ -160,13 +154,6 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, | |||
160 | } | 154 | } |
161 | } | 155 | } |
162 | 156 | ||
163 | /* now that the vqs are all set, boot the remote processor */ | ||
164 | ret = rproc_boot_nowait(rproc); | ||
165 | if (ret) { | ||
166 | dev_err(&rproc->dev, "rproc_boot() failed %d\n", ret); | ||
167 | goto error; | ||
168 | } | ||
169 | |||
170 | return 0; | 157 | return 0; |
171 | 158 | ||
172 | error: | 159 | error: |
@@ -239,8 +226,8 @@ static int rproc_virtio_finalize_features(struct virtio_device *vdev) | |||
239 | return 0; | 226 | return 0; |
240 | } | 227 | } |
241 | 228 | ||
242 | static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset, | 229 | static void rproc_virtio_get(struct virtio_device *vdev, unsigned int offset, |
243 | void *buf, unsigned len) | 230 | void *buf, unsigned int len) |
244 | { | 231 | { |
245 | struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); | 232 | struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); |
246 | struct fw_rsc_vdev *rsc; | 233 | struct fw_rsc_vdev *rsc; |
@@ -257,8 +244,8 @@ static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset, | |||
257 | memcpy(buf, cfg + offset, len); | 244 | memcpy(buf, cfg + offset, len); |
258 | } | 245 | } |
259 | 246 | ||
260 | static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset, | 247 | static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset, |
261 | const void *buf, unsigned len) | 248 | const void *buf, unsigned int len) |
262 | { | 249 | { |
263 | struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); | 250 | struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); |
264 | struct fw_rsc_vdev *rsc; | 251 | struct fw_rsc_vdev *rsc; |
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index 6f056caa8a56..ae8963fcc8c8 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c | |||
@@ -262,7 +262,7 @@ static int st_rproc_probe(struct platform_device *pdev) | |||
262 | return 0; | 262 | return 0; |
263 | 263 | ||
264 | free_rproc: | 264 | free_rproc: |
265 | rproc_put(rproc); | 265 | rproc_free(rproc); |
266 | return ret; | 266 | return ret; |
267 | } | 267 | } |
268 | 268 | ||
@@ -277,7 +277,7 @@ static int st_rproc_remove(struct platform_device *pdev) | |||
277 | 277 | ||
278 | of_reserved_mem_device_release(&pdev->dev); | 278 | of_reserved_mem_device_release(&pdev->dev); |
279 | 279 | ||
280 | rproc_put(rproc); | 280 | rproc_free(rproc); |
281 | 281 | ||
282 | return 0; | 282 | return 0; |
283 | } | 283 | } |
diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c index 53dc17bdd54e..03d69a9a3c5b 100644 --- a/drivers/remoteproc/ste_modem_rproc.c +++ b/drivers/remoteproc/ste_modem_rproc.c | |||
@@ -257,7 +257,7 @@ static int sproc_drv_remove(struct platform_device *pdev) | |||
257 | rproc_del(sproc->rproc); | 257 | rproc_del(sproc->rproc); |
258 | dma_free_coherent(sproc->rproc->dev.parent, SPROC_FW_SIZE, | 258 | dma_free_coherent(sproc->rproc->dev.parent, SPROC_FW_SIZE, |
259 | sproc->fw_addr, sproc->fw_dma_addr); | 259 | sproc->fw_addr, sproc->fw_dma_addr); |
260 | rproc_put(sproc->rproc); | 260 | rproc_free(sproc->rproc); |
261 | 261 | ||
262 | mdev->drv_data = NULL; | 262 | mdev->drv_data = NULL; |
263 | 263 | ||
@@ -325,7 +325,7 @@ free_mem: | |||
325 | free_rproc: | 325 | free_rproc: |
326 | /* Reset device data upon error */ | 326 | /* Reset device data upon error */ |
327 | mdev->drv_data = NULL; | 327 | mdev->drv_data = NULL; |
328 | rproc_put(rproc); | 328 | rproc_free(rproc); |
329 | return err; | 329 | return err; |
330 | } | 330 | } |
331 | 331 | ||
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 02d271d101b4..18175d0331fd 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c | |||
@@ -167,6 +167,8 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) | |||
167 | goto err; | 167 | goto err; |
168 | } | 168 | } |
169 | 169 | ||
170 | rproc->auto_boot = false; | ||
171 | |||
170 | wkupm3 = rproc->priv; | 172 | wkupm3 = rproc->priv; |
171 | wkupm3->rproc = rproc; | 173 | wkupm3->rproc = rproc; |
172 | wkupm3->pdev = pdev; | 174 | wkupm3->pdev = pdev; |
@@ -206,7 +208,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) | |||
206 | return 0; | 208 | return 0; |
207 | 209 | ||
208 | err_put_rproc: | 210 | err_put_rproc: |
209 | rproc_put(rproc); | 211 | rproc_free(rproc); |
210 | err: | 212 | err: |
211 | pm_runtime_put_noidle(dev); | 213 | pm_runtime_put_noidle(dev); |
212 | pm_runtime_disable(dev); | 214 | pm_runtime_disable(dev); |
@@ -218,7 +220,7 @@ static int wkup_m3_rproc_remove(struct platform_device *pdev) | |||
218 | struct rproc *rproc = platform_get_drvdata(pdev); | 220 | struct rproc *rproc = platform_get_drvdata(pdev); |
219 | 221 | ||
220 | rproc_del(rproc); | 222 | rproc_del(rproc); |
221 | rproc_put(rproc); | 223 | rproc_free(rproc); |
222 | pm_runtime_put_sync(&pdev->dev); | 224 | pm_runtime_put_sync(&pdev->dev); |
223 | pm_runtime_disable(&pdev->dev); | 225 | pm_runtime_disable(&pdev->dev); |
224 | 226 | ||
diff --git a/include/linux/platform_data/remoteproc-omap.h b/include/linux/platform_data/remoteproc-omap.h index bfbd12b41162..71a1b2399c48 100644 --- a/include/linux/platform_data/remoteproc-omap.h +++ b/include/linux/platform_data/remoteproc-omap.h | |||
@@ -39,9 +39,9 @@ struct omap_rproc_pdata { | |||
39 | const char *firmware; | 39 | const char *firmware; |
40 | const char *mbox_name; | 40 | const char *mbox_name; |
41 | const struct rproc_ops *ops; | 41 | const struct rproc_ops *ops; |
42 | int (*device_enable) (struct platform_device *pdev); | 42 | int (*device_enable)(struct platform_device *pdev); |
43 | int (*device_shutdown) (struct platform_device *pdev); | 43 | int (*device_shutdown)(struct platform_device *pdev); |
44 | void(*set_bootaddr)(u32); | 44 | void (*set_bootaddr)(u32); |
45 | }; | 45 | }; |
46 | 46 | ||
47 | #if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE) | 47 | #if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE) |
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 1c457a8dd5a6..930023b7c825 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h | |||
@@ -118,7 +118,7 @@ enum fw_resource_type { | |||
118 | RSC_LAST = 4, | 118 | RSC_LAST = 4, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | #define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) | 121 | #define FW_RSC_ADDR_ANY (-1) |
122 | 122 | ||
123 | /** | 123 | /** |
124 | * struct fw_rsc_carveout - physically contiguous memory request | 124 | * struct fw_rsc_carveout - physically contiguous memory request |
@@ -241,7 +241,7 @@ struct fw_rsc_trace { | |||
241 | * @notifyid is a unique rproc-wide notify index for this vring. This notify | 241 | * @notifyid is a unique rproc-wide notify index for this vring. This notify |
242 | * index is used when kicking a remote processor, to let it know that this | 242 | * index is used when kicking a remote processor, to let it know that this |
243 | * vring is triggered. | 243 | * vring is triggered. |
244 | * @reserved: reserved (must be zero) | 244 | * @pa: physical address |
245 | * | 245 | * |
246 | * This descriptor is not a resource entry by itself; it is part of the | 246 | * This descriptor is not a resource entry by itself; it is part of the |
247 | * vdev resource type (see below). | 247 | * vdev resource type (see below). |
@@ -255,7 +255,7 @@ struct fw_rsc_vdev_vring { | |||
255 | u32 align; | 255 | u32 align; |
256 | u32 num; | 256 | u32 num; |
257 | u32 notifyid; | 257 | u32 notifyid; |
258 | u32 reserved; | 258 | u32 pa; |
259 | } __packed; | 259 | } __packed; |
260 | 260 | ||
261 | /** | 261 | /** |
@@ -409,7 +409,6 @@ enum rproc_crash_type { | |||
409 | * @max_notifyid: largest allocated notify id. | 409 | * @max_notifyid: largest allocated notify id. |
410 | * @table_ptr: pointer to the resource table in effect | 410 | * @table_ptr: pointer to the resource table in effect |
411 | * @cached_table: copy of the resource table | 411 | * @cached_table: copy of the resource table |
412 | * @table_csum: checksum of the resource table | ||
413 | * @has_iommu: flag to indicate if remote processor is behind an MMU | 412 | * @has_iommu: flag to indicate if remote processor is behind an MMU |
414 | */ | 413 | */ |
415 | struct rproc { | 414 | struct rproc { |
@@ -435,14 +434,14 @@ struct rproc { | |||
435 | struct idr notifyids; | 434 | struct idr notifyids; |
436 | int index; | 435 | int index; |
437 | struct work_struct crash_handler; | 436 | struct work_struct crash_handler; |
438 | unsigned crash_cnt; | 437 | unsigned int crash_cnt; |
439 | struct completion crash_comp; | 438 | struct completion crash_comp; |
440 | bool recovery_disabled; | 439 | bool recovery_disabled; |
441 | int max_notifyid; | 440 | int max_notifyid; |
442 | struct resource_table *table_ptr; | 441 | struct resource_table *table_ptr; |
443 | struct resource_table *cached_table; | 442 | struct resource_table *cached_table; |
444 | u32 table_csum; | ||
445 | bool has_iommu; | 443 | bool has_iommu; |
444 | bool auto_boot; | ||
446 | }; | 445 | }; |
447 | 446 | ||
448 | /* we currently support only two vrings per rvdev */ | 447 | /* we currently support only two vrings per rvdev */ |
@@ -489,11 +488,12 @@ struct rproc_vdev { | |||
489 | 488 | ||
490 | struct rproc *rproc_get_by_phandle(phandle phandle); | 489 | struct rproc *rproc_get_by_phandle(phandle phandle); |
491 | struct rproc *rproc_alloc(struct device *dev, const char *name, | 490 | struct rproc *rproc_alloc(struct device *dev, const char *name, |
492 | const struct rproc_ops *ops, | 491 | const struct rproc_ops *ops, |
493 | const char *firmware, int len); | 492 | const char *firmware, int len); |
494 | void rproc_put(struct rproc *rproc); | 493 | void rproc_put(struct rproc *rproc); |
495 | int rproc_add(struct rproc *rproc); | 494 | int rproc_add(struct rproc *rproc); |
496 | int rproc_del(struct rproc *rproc); | 495 | int rproc_del(struct rproc *rproc); |
496 | void rproc_free(struct rproc *rproc); | ||
497 | 497 | ||
498 | int rproc_boot(struct rproc *rproc); | 498 | int rproc_boot(struct rproc *rproc); |
499 | void rproc_shutdown(struct rproc *rproc); | 499 | void rproc_shutdown(struct rproc *rproc); |