aboutsummaryrefslogtreecommitdiffci
path: root/patches/remoteproc/0009-remoteproc-core-Allow-restarting-detached-remoteproc.patch
blob: 47f81de84dad157b3199a87aa6f4fe936973d2de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
At the moment, the remoteproc core supports only one auto boot "strategy":
A remoteproc that is already running during boot ("detached") is attached,
a remoteproc that is offline is started after loading the firmware. This
works if the firmware loaded during boot is the same that we would start
later, but it could also be outdated or a reduced size version that is
missing some functionality. In this case, the best option is to try
restarting it with new firmware - assuming that it is available while
booting.

Add support for this alternative behavior by replacing the "auto_boot" bool
with a more explicit enum rproc_auto_boot.

For RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE, try requesting the firmware
early and - if successful - perform a clean stop of the remoteproc so that
it can be restarted with the new firmware afterwards. A remoteproc driver
making use of this functionality must handle the stop() callback being
called during the initial detached state.

Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
 drivers/remoteproc/imx_rproc.c          |  8 +++--
 drivers/remoteproc/ingenic_rproc.c      |  5 ++-
 drivers/remoteproc/pru_rproc.c          |  2 +-
 drivers/remoteproc/qcom_q6v5_adsp.c     |  5 ++-
 drivers/remoteproc/qcom_q6v5_mss.c      |  2 +-
 drivers/remoteproc/qcom_q6v5_pas.c      |  5 ++-
 drivers/remoteproc/rcar_rproc.c         |  2 +-
 drivers/remoteproc/remoteproc_core.c    | 47 ++++++++++++++++++-------
 drivers/remoteproc/stm32_rproc.c        |  8 +++--
 drivers/remoteproc/wkup_m3_rproc.c      |  2 +-
 drivers/remoteproc/xlnx_r5_remoteproc.c |  2 +-
 include/linux/remoteproc.h              | 23 +++++++++++-
 12 files changed, 85 insertions(+), 26 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 0dd80e688b0ea3..d5758207d155b6 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -1288,8 +1288,12 @@ static int imx_rproc_probe(struct platform_device *pdev)
 			return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to enable clock\n");
 	}
 
-	if (rproc->state != RPROC_DETACHED)
-		rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot");
+	if (rproc->state != RPROC_DETACHED) {
+		if (of_property_read_bool(np, "fsl,auto-boot"))
+			rproc->auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
+		else
+			rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
+	}
 
 	if (dcfg->flags & IMX_RPROC_NEED_SYSTEM_OFF) {
 		/*
diff --git a/drivers/remoteproc/ingenic_rproc.c b/drivers/remoteproc/ingenic_rproc.c
index 1b78d8ddeacfd5..351b9529713790 100644
--- a/drivers/remoteproc/ingenic_rproc.c
+++ b/drivers/remoteproc/ingenic_rproc.c
@@ -177,7 +177,10 @@ static int ingenic_rproc_probe(struct platform_device *pdev)
 	if (!rproc)
 		return -ENOMEM;
 
-	rproc->auto_boot = auto_boot;
+	if (auto_boot)
+		rproc->auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
+	else
+		rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 
 	vpu = rproc->priv;
 	vpu->dev = &pdev->dev;
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index a4636c7bc6b7be..0928a75916f352 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -1029,7 +1029,7 @@ static int pru_rproc_probe(struct platform_device *pdev)
 	 * remote-processor as part of its state machine either through the
 	 * remoteproc sysfs interface or through the equivalent kernel API.
 	 */
-	rproc->auto_boot = false;
+	rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 
 	pru = rproc->priv;
 	pru->dev = dev;
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index b5c8d6d38c9cbc..7184f73be69105 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -673,7 +673,10 @@ static int adsp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	rproc->auto_boot = desc->auto_boot;
+	if (desc->auto_boot)
+		rproc->auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
+	else
+		rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 	rproc->has_iommu = desc->has_iommu;
 	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
 
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index ae78f5c7c1b69e..606896500ec310 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -2095,7 +2095,7 @@ static int q6v5_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	rproc->auto_boot = false;
+	rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
 
 	qproc = rproc->priv;
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index da27d1d3c9da64..1327e187514821 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -774,7 +774,10 @@ static int qcom_pas_probe(struct platform_device *pdev)
 	}
 
 	rproc->has_iommu = of_property_present(pdev->dev.of_node, "iommus");
-	rproc->auto_boot = desc->auto_boot;
+	if (desc->auto_boot)
+		rproc->auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
+	else
+		rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
 
 	pas = rproc->priv;
diff --git a/drivers/remoteproc/rcar_rproc.c b/drivers/remoteproc/rcar_rproc.c
index 3c25625f966dcb..99a26a05165883 100644
--- a/drivers/remoteproc/rcar_rproc.c
+++ b/drivers/remoteproc/rcar_rproc.c
@@ -172,7 +172,7 @@ static int rcar_rproc_probe(struct platform_device *pdev)
 	dev_set_drvdata(dev, rproc);
 
 	/* Manually start the rproc */
-	rproc->auto_boot = false;
+	rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 
 	ret = devm_rproc_add(dev, rproc);
 	if (ret) {
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index b087ed21858a8c..ec75659957033b 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1683,7 +1683,8 @@ static int rproc_trigger_auto_boot(struct rproc *rproc)
 {
 	int ret;
 
-	if (rproc->state == RPROC_DETACHED) {
+	if (rproc->state == RPROC_DETACHED &&
+	    rproc->auto_boot != RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE) {
 		schedule_work(&rproc->attach_work);
 		return 0;
 	}
@@ -1708,8 +1709,9 @@ static int rproc_stop(struct rproc *rproc, bool crashed)
 	if (!rproc->ops->stop)
 		return -EINVAL;
 
-	/* Stop any subdevices for the remote processor */
-	rproc_stop_subdevices(rproc, crashed);
+	/* Stop any subdevices for the remote processor if it was attached */
+	if (rproc->state != RPROC_DETACHED)
+		rproc_stop_subdevices(rproc, crashed);
 
 	/* the installed resource table is no longer accessible */
 	ret = rproc_reset_rsc_table_on_stop(rproc);
@@ -1726,7 +1728,8 @@ static int rproc_stop(struct rproc *rproc, bool crashed)
 		return ret;
 	}
 
-	rproc_unprepare_subdevices(rproc);
+	if (rproc->state != RPROC_DETACHED)
+		rproc_unprepare_subdevices(rproc);
 
 	rproc->state = RPROC_OFFLINE;
 
@@ -1903,9 +1906,9 @@ static void rproc_crash_handler_work(struct work_struct *work)
  */
 int rproc_boot(struct rproc *rproc)
 {
-	const struct firmware *firmware_p;
+	const struct firmware *firmware_p = NULL;
 	struct device *dev;
-	int ret;
+	int ret, fw_ret = 1;
 
 	if (!rproc) {
 		pr_err("invalid rproc handle\n");
@@ -1932,6 +1935,19 @@ int rproc_boot(struct rproc *rproc)
 		goto unlock_mutex;
 	}
 
+	/* Check early if we have firmware avilable if needed */
+	if (rproc->auto_boot == RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE &&
+	    rproc->state == RPROC_DETACHED) {
+		fw_ret = request_firmware(&firmware_p, rproc->firmware, dev);
+		if (fw_ret == 0) {
+			dev_info(dev, "restarting %s with new firmware\n", rproc->name);
+
+			ret = rproc_stop(rproc, false);
+			if (ret)
+				goto downref_rproc;
+		}
+	}
+
 	if (rproc->state == RPROC_DETACHED) {
 		dev_info(dev, "attaching to %s\n", rproc->name);
 
@@ -1939,19 +1955,20 @@ int rproc_boot(struct rproc *rproc)
 	} else {
 		dev_info(dev, "powering up %s\n", rproc->name);
 
-		/* load firmware */
-		ret = request_firmware(&firmware_p, rproc->firmware, dev);
-		if (ret < 0) {
-			dev_err(dev, "request_firmware failed: %d\n", ret);
+		/* load firmware (if not already happened above) */
+		if (fw_ret == 1)
+			fw_ret = request_firmware(&firmware_p, rproc->firmware, dev);
+		if (fw_ret < 0) {
+			dev_err(dev, "request_firmware failed: %d\n", fw_ret);
+			ret = fw_ret;
 			goto downref_rproc;
 		}
 
 		ret = rproc_fw_boot(rproc, firmware_p);
-
-		release_firmware(firmware_p);
 	}
 
 downref_rproc:
+	release_firmware(firmware_p);
 	if (ret)
 		atomic_dec(&rproc->power);
 unlock_mutex:
@@ -2259,6 +2276,10 @@ static int rproc_validate(struct rproc *rproc)
 		return -EINVAL;
 	}
 
+	if (rproc->auto_boot == RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE &&
+	    (!rproc->ops->stop || !rproc->ops->start || !rproc->ops->attach))
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -2470,7 +2491,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 		return NULL;
 
 	rproc->priv = &rproc[1];
-	rproc->auto_boot = true;
+	rproc->auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
 	rproc->elf_class = ELFCLASSNONE;
 	rproc->elf_machine = EM_NONE;
 
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 632614013dc652..891fc17f8a63eb 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -696,7 +696,8 @@ static int stm32_rproc_get_syscon(struct device_node *np, const char *prop,
 }
 
 static int stm32_rproc_parse_dt(struct platform_device *pdev,
-				struct stm32_rproc *ddata, bool *auto_boot)
+				struct stm32_rproc *ddata,
+				enum rproc_auto_boot *auto_boot)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
@@ -777,7 +778,10 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
 	if (err)
 		dev_info(dev, "failed to get pdds\n");
 
-	*auto_boot = of_property_read_bool(np, "st,auto-boot");
+	if (of_property_read_bool(np, "st,auto-boot"))
+		*auto_boot = RPROC_AUTO_BOOT_ATTACH_OR_START;
+	else
+		*auto_boot = RPROC_AUTO_BOOT_DISABLED;
 
 	/*
 	 * See if we can check the M4 status, i.e if it was started
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index 2d5bfbefcacc5b..8815648295c892 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -170,7 +170,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev)
 	if (!rproc)
 		return -ENOMEM;
 
-	rproc->auto_boot = false;
+	rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 	rproc->sysfs_read_only = true;
 
 	wkupm3 = rproc->priv;
diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c
index 50a9974f3202e6..4e230838a24abd 100644
--- a/drivers/remoteproc/xlnx_r5_remoteproc.c
+++ b/drivers/remoteproc/xlnx_r5_remoteproc.c
@@ -931,7 +931,7 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
 
 	r5_rproc->recovery_disabled = true;
 	r5_rproc->has_iommu = false;
-	r5_rproc->auto_boot = false;
+	r5_rproc->auto_boot = RPROC_AUTO_BOOT_DISABLED;
 
 	/* attempt to boot automatically if the firmware-name is provided */
 	if (fw_name)
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index b4795698d8c2a4..c40b18d120ab46 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -503,6 +503,27 @@ enum rproc_features {
 	RPROC_MAX_FEATURES,
 };
 
+/**
+ * enum rproc_auto_boot - auto boot strategy for remoteproc during initial boot
+ *
+ * @RPROC_AUTO_BOOT_DISABLED: The remoteproc will be left offline (or detached).
+ * @RPROC_AUTO_BOOT_ATTACH_OR_START: The remoteproc will be attached (if it is
+ *				     already running). Otherwise, it will be
+ *				     started with new loaded firmware.
+ * @RPROC_FEAT_REBOOT_IF_FW_AVAILABLE: The remoteproc will be restarted if
+ *				       requesting new firmware succeeds. If
+ *				       the firmware is missing and the
+ *				       remoteproc is already running, it will
+ *				       be attached instead. A remoteproc
+ *				       implementing this must handle stop()
+ *				       being called in detached state.
+ */
+enum rproc_auto_boot {
+	RPROC_AUTO_BOOT_DISABLED,
+	RPROC_AUTO_BOOT_ATTACH_OR_START,
+	RPROC_AUTO_BOOT_RESTART_IF_FW_AVAILABLE,
+};
+
 /**
  * struct rproc - represents a physical remote processor device
  * @node: list node of this rproc object
@@ -577,7 +598,7 @@ struct rproc {
 	struct resource_table *cached_table;
 	size_t table_sz;
 	bool has_iommu;
-	bool auto_boot;
+	enum rproc_auto_boot auto_boot;
 	bool sysfs_read_only;
 	struct list_head dump_segments;
 	int nb_vdev;