blob: 3233ff80419b2f4f667b5ec92ab00bc57a181221 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Nishanth Menon08b9dc22015-09-17 15:42:39 -05002/*
3 * (C) Copyright 2015
Nishanth Menoneaa39c62023-11-01 15:56:03 -05004 * Texas Instruments Incorporated - https://www.ti.com/
Nishanth Menon08b9dc22015-09-17 15:42:39 -05005 */
Patrick Delaunay81313352021-04-27 11:02:19 +02006
7#define LOG_CATEGORY UCLASS_REMOTEPROC
8
Nishanth Menon08b9dc22015-09-17 15:42:39 -05009#define pr_fmt(fmt) "%s: " fmt, __func__
Keerthy844db202022-01-27 13:16:55 +010010#include <elf.h>
Nishanth Menon08b9dc22015-09-17 15:42:39 -050011#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Nishanth Menon08b9dc22015-09-17 15:42:39 -050013#include <malloc.h>
Keerthy844db202022-01-27 13:16:55 +010014#include <virtio_ring.h>
MD Danish Anwardb1e4db2024-03-21 15:58:19 +053015#include <fs_loader.h>
Nishanth Menon08b9dc22015-09-17 15:42:39 -050016#include <remoteproc.h>
17#include <asm/io.h>
18#include <dm/device-internal.h>
19#include <dm.h>
20#include <dm/uclass.h>
21#include <dm/uclass-internal.h>
Keerthy844db202022-01-27 13:16:55 +010022#include <linux/compat.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060023#include <linux/printk.h>
Keerthy844db202022-01-27 13:16:55 +010024
25DECLARE_GLOBAL_DATA_PTR;
26
27struct resource_table {
28 u32 ver;
29 u32 num;
30 u32 reserved[2];
31 u32 offset[0];
32} __packed;
33
34typedef int (*handle_resource_t) (struct udevice *, void *, int offset, int avail);
35
36static struct resource_table *rsc_table;
Nishanth Menon08b9dc22015-09-17 15:42:39 -050037
Nishanth Menon08b9dc22015-09-17 15:42:39 -050038/**
39 * for_each_remoteproc_device() - iterate through the list of rproc devices
40 * @fn: check function to call per match, if this function returns fail,
41 * iteration is aborted with the resultant error value
42 * @skip_dev: Device to skip calling the callback about.
43 * @data: Data to pass to the callback function
44 *
45 * Return: 0 if none of the callback returned a non 0 result, else returns the
46 * result from the callback function
47 */
48static int for_each_remoteproc_device(int (*fn) (struct udevice *dev,
49 struct dm_rproc_uclass_pdata *uc_pdata,
50 const void *data),
51 struct udevice *skip_dev,
52 const void *data)
53{
54 struct udevice *dev;
55 struct dm_rproc_uclass_pdata *uc_pdata;
56 int ret;
57
58 for (ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); dev;
59 ret = uclass_find_next_device(&dev)) {
60 if (ret || dev == skip_dev)
61 continue;
Simon Glass71fa5b42020-12-03 16:55:18 -070062 uc_pdata = dev_get_uclass_plat(dev);
Nishanth Menon08b9dc22015-09-17 15:42:39 -050063 ret = fn(dev, uc_pdata, data);
64 if (ret)
65 return ret;
66 }
67
68 return 0;
69}
70
71/**
72 * _rproc_name_is_unique() - iteration helper to check if rproc name is unique
73 * @dev: device that we are checking name for
74 * @uc_pdata: uclass platform data
75 * @data: compare data (this is the name we want to ensure is unique)
76 *
77 * Return: 0 is there is no match(is unique); if there is a match(we dont
78 * have a unique name), return -EINVAL.
79 */
80static int _rproc_name_is_unique(struct udevice *dev,
81 struct dm_rproc_uclass_pdata *uc_pdata,
82 const void *data)
83{
84 const char *check_name = data;
85
86 /* devices not yet populated with data - so skip them */
Nishanth Menon3ab6a4e2015-11-30 22:05:58 -060087 if (!uc_pdata->name || !check_name)
Nishanth Menon08b9dc22015-09-17 15:42:39 -050088 return 0;
89
90 /* Return 0 to search further if we dont match */
91 if (strlen(uc_pdata->name) != strlen(check_name))
92 return 0;
93
94 if (!strcmp(uc_pdata->name, check_name))
95 return -EINVAL;
96
97 return 0;
98}
99
100/**
101 * rproc_name_is_unique() - Check if the rproc name is unique
102 * @check_dev: Device we are attempting to ensure is unique
103 * @check_name: Name we are trying to ensure is unique.
104 *
105 * Return: true if we have a unique name, false if name is not unique.
106 */
107static bool rproc_name_is_unique(struct udevice *check_dev,
108 const char *check_name)
109{
110 int ret;
111
112 ret = for_each_remoteproc_device(_rproc_name_is_unique,
113 check_dev, check_name);
114 return ret ? false : true;
115}
116
117/**
118 * rproc_pre_probe() - Pre probe accessor for the uclass
119 * @dev: device for which we are preprobing
120 *
121 * Parses and fills up the uclass pdata for use as needed by core and
122 * remote proc drivers.
123 *
124 * Return: 0 if all wernt ok, else appropriate error value.
125 */
126static int rproc_pre_probe(struct udevice *dev)
127{
128 struct dm_rproc_uclass_pdata *uc_pdata;
129 const struct dm_rproc_ops *ops;
130
Simon Glass71fa5b42020-12-03 16:55:18 -0700131 uc_pdata = dev_get_uclass_plat(dev);
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500132
133 /* See if we need to populate via fdt */
134
Simon Glass95588622020-12-22 19:30:28 -0700135 if (!dev_get_plat(dev)) {
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500136#if CONFIG_IS_ENABLED(OF_CONTROL)
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500137 bool tmp;
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500138 debug("'%s': using fdt\n", dev->name);
Patrick Delaunayc249ae52021-09-20 17:56:06 +0200139 uc_pdata->name = dev_read_string(dev, "remoteproc-name");
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500140
141 /* Default is internal memory mapped */
142 uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
Patrick Delaunayc249ae52021-09-20 17:56:06 +0200143 tmp = dev_read_bool(dev, "remoteproc-internal-memory-mapped");
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500144 if (tmp)
145 uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
146#else
147 /* Nothing much we can do about this, can we? */
148 return -EINVAL;
149#endif
150
151 } else {
Simon Glass95588622020-12-22 19:30:28 -0700152 struct dm_rproc_uclass_pdata *pdata = dev_get_plat(dev);
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500153
154 debug("'%s': using legacy data\n", dev->name);
155 if (pdata->name)
156 uc_pdata->name = pdata->name;
157 uc_pdata->mem_type = pdata->mem_type;
158 uc_pdata->driver_plat_data = pdata->driver_plat_data;
159 }
160
MD Danish Anwar2f07a6d2024-08-07 14:38:29 +0530161 /* Else try using a combination of device Name and devices's parent's name */
162 if (!uc_pdata->name) {
163 /* 2 in the rproc_name_size indicates 1 for null and one for '-' */
164 int rproc_name_size = strlen(dev->name) + strlen(dev->parent->name) + 2;
165 char *buf;
166
167 buf = malloc(rproc_name_size);
168 if (!buf)
169 return -ENOMEM;
170
171 snprintf(buf, rproc_name_size, "%s-%s", dev->name, dev->parent->name);
172 uc_pdata->name = buf;
173 }
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500174 if (!uc_pdata->name) {
175 debug("Unnamed device!");
176 return -EINVAL;
177 }
178
179 if (!rproc_name_is_unique(dev, uc_pdata->name)) {
180 debug("%s duplicate name '%s'\n", dev->name, uc_pdata->name);
181 return -EINVAL;
182 }
183
184 ops = rproc_get_ops(dev);
185 if (!ops) {
186 debug("%s driver has no ops?\n", dev->name);
187 return -EINVAL;
188 }
189
190 if (!ops->load || !ops->start) {
191 debug("%s driver has missing mandatory ops?\n", dev->name);
192 return -EINVAL;
193 }
194
195 return 0;
196}
197
198/**
199 * rproc_post_probe() - post probe accessor for the uclass
200 * @dev: deivce we finished probing
201 *
202 * initiate init function after the probe is completed. This allows
203 * the remote processor drivers to split up the initializations between
204 * probe and init as needed.
205 *
206 * Return: if the remote proc driver has a init routine, invokes it and
207 * hands over the return value. overall, 0 if all went well, else appropriate
208 * error value.
209 */
210static int rproc_post_probe(struct udevice *dev)
211{
212 const struct dm_rproc_ops *ops;
213
214 ops = rproc_get_ops(dev);
215 if (!ops) {
216 debug("%s driver has no ops?\n", dev->name);
217 return -EINVAL;
218 }
219
220 if (ops->init)
221 return ops->init(dev);
222
223 return 0;
224}
225
Keerthy844db202022-01-27 13:16:55 +0100226/**
227 * rproc_add_res() - After parsing the resource table add the mappings
228 * @dev: device we finished probing
229 * @mapping: rproc_mem_entry for the resource
230 *
231 * Return: if the remote proc driver has a add_res routine, invokes it and
232 * hands over the return value. overall, 0 if all went well, else appropriate
233 * error value.
234 */
235static int rproc_add_res(struct udevice *dev, struct rproc_mem_entry *mapping)
236{
237 const struct dm_rproc_ops *ops = rproc_get_ops(dev);
238
239 if (!ops->add_res)
240 return -ENOSYS;
241
242 return ops->add_res(dev, mapping);
243}
244
245/**
246 * rproc_alloc_mem() - After parsing the resource table allocat mem
247 * @dev: device we finished probing
248 * @len: rproc_mem_entry for the resource
249 * @align: alignment for the resource
250 *
251 * Return: if the remote proc driver has a add_res routine, invokes it and
252 * hands over the return value. overall, 0 if all went well, else appropriate
253 * error value.
254 */
255static void *rproc_alloc_mem(struct udevice *dev, unsigned long len,
256 unsigned long align)
257{
258 const struct dm_rproc_ops *ops;
259
260 ops = rproc_get_ops(dev);
261 if (!ops) {
262 debug("%s driver has no ops?\n", dev->name);
263 return NULL;
264 }
265
266 if (ops->alloc_mem)
267 return ops->alloc_mem(dev, len, align);
268
269 return NULL;
270}
271
272/**
273 * rproc_config_pagetable() - Configure page table for remote processor
274 * @dev: device we finished probing
275 * @virt: Virtual address of the resource
276 * @phys: Physical address the resource
277 * @len: length the resource
278 *
279 * Return: if the remote proc driver has a add_res routine, invokes it and
280 * hands over the return value. overall, 0 if all went well, else appropriate
281 * error value.
282 */
283static int rproc_config_pagetable(struct udevice *dev, unsigned int virt,
284 unsigned int phys, unsigned int len)
285{
286 const struct dm_rproc_ops *ops;
287
288 ops = rproc_get_ops(dev);
289 if (!ops) {
290 debug("%s driver has no ops?\n", dev->name);
291 return -EINVAL;
292 }
293
294 if (ops->config_pagetable)
295 return ops->config_pagetable(dev, virt, phys, len);
296
297 return 0;
298}
299
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500300UCLASS_DRIVER(rproc) = {
301 .id = UCLASS_REMOTEPROC,
302 .name = "remoteproc",
303 .flags = DM_UC_FLAG_SEQ_ALIAS,
304 .pre_probe = rproc_pre_probe,
305 .post_probe = rproc_post_probe,
Simon Glass33b2efb2020-12-03 16:55:22 -0700306 .per_device_plat_auto = sizeof(struct dm_rproc_uclass_pdata),
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500307};
308
309/* Remoteproc subsystem access functions */
310/**
311 * _rproc_probe_dev() - iteration helper to probe a rproc device
312 * @dev: device to probe
313 * @uc_pdata: uclass data allocated for the device
314 * @data: unused
315 *
316 * Return: 0 if all ok, else appropriate error value.
317 */
318static int _rproc_probe_dev(struct udevice *dev,
319 struct dm_rproc_uclass_pdata *uc_pdata,
320 const void *data)
321{
322 int ret;
323
324 ret = device_probe(dev);
325
326 if (ret)
327 debug("%s: Failed to initialize - %d\n", dev->name, ret);
328 return ret;
329}
330
331/**
332 * _rproc_dev_is_probed() - check if the device has been probed
333 * @dev: device to check
334 * @uc_pdata: unused
335 * @data: unused
336 *
337 * Return: -EAGAIN if not probed else return 0
338 */
339static int _rproc_dev_is_probed(struct udevice *dev,
340 struct dm_rproc_uclass_pdata *uc_pdata,
341 const void *data)
342{
Simon Glass6211d762020-12-19 10:40:10 -0700343 if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500344 return 0;
345
346 return -EAGAIN;
347}
348
349bool rproc_is_initialized(void)
350{
351 int ret = for_each_remoteproc_device(_rproc_dev_is_probed, NULL, NULL);
352 return ret ? false : true;
353}
354
355int rproc_init(void)
356{
357 int ret;
358
359 if (rproc_is_initialized()) {
360 debug("Already initialized\n");
361 return -EINVAL;
362 }
363
364 ret = for_each_remoteproc_device(_rproc_probe_dev, NULL, NULL);
365 return ret;
366}
367
Lokesh Vutladdca80e2018-08-27 15:57:50 +0530368int rproc_dev_init(int id)
369{
370 struct udevice *dev = NULL;
371 int ret;
372
373 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
374 if (ret) {
375 debug("Unknown remote processor id '%d' requested(%d)\n",
376 id, ret);
377 return ret;
378 }
379
380 ret = device_probe(dev);
381 if (ret)
382 debug("%s: Failed to initialize - %d\n", dev->name, ret);
383
384 return ret;
385}
386
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500387int rproc_load(int id, ulong addr, ulong size)
388{
389 struct udevice *dev = NULL;
390 struct dm_rproc_uclass_pdata *uc_pdata;
391 const struct dm_rproc_ops *ops;
392 int ret;
393
394 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
395 if (ret) {
396 debug("Unknown remote processor id '%d' requested(%d)\n",
397 id, ret);
398 return ret;
399 }
400
Simon Glass71fa5b42020-12-03 16:55:18 -0700401 uc_pdata = dev_get_uclass_plat(dev);
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500402
403 ops = rproc_get_ops(dev);
404 if (!ops) {
405 debug("%s driver has no ops?\n", dev->name);
406 return -EINVAL;
407 }
408
409 debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n",
410 uc_pdata->name, addr, size);
411 if (ops->load)
412 return ops->load(dev, addr, size);
413
414 debug("%s: data corruption?? mandatory function is missing!\n",
415 dev->name);
416
417 return -EINVAL;
418};
419
420/*
421 * Completely internal helper enums..
422 * Keeping this isolated helps this code evolve independent of other
423 * parts..
424 */
425enum rproc_ops {
426 RPROC_START,
427 RPROC_STOP,
428 RPROC_RESET,
429 RPROC_PING,
430 RPROC_RUNNING,
431};
432
433/**
434 * _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback
435 * @id: id of the remote processor
436 * @op: one of rproc_ops that indicate what operation to invoke
437 *
438 * Most of the checks and verification for remoteproc operations are more
439 * or less same for almost all operations. This allows us to put a wrapper
440 * and use the common checks to allow the driver to function appropriately.
441 *
442 * Return: 0 if all ok, else appropriate error value.
443 */
444static int _rproc_ops_wrapper(int id, enum rproc_ops op)
445{
446 struct udevice *dev = NULL;
447 struct dm_rproc_uclass_pdata *uc_pdata;
448 const struct dm_rproc_ops *ops;
449 int (*fn)(struct udevice *dev);
450 bool mandatory = false;
451 char *op_str;
452 int ret;
453
454 ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
455 if (ret) {
456 debug("Unknown remote processor id '%d' requested(%d)\n",
457 id, ret);
458 return ret;
459 }
460
Simon Glass71fa5b42020-12-03 16:55:18 -0700461 uc_pdata = dev_get_uclass_plat(dev);
Nishanth Menon08b9dc22015-09-17 15:42:39 -0500462
463 ops = rproc_get_ops(dev);
464 if (!ops) {
465 debug("%s driver has no ops?\n", dev->name);
466 return -EINVAL;
467 }
468 switch (op) {
469 case RPROC_START:
470 fn = ops->start;
471 mandatory = true;
472 op_str = "Starting";
473 break;
474 case RPROC_STOP:
475 fn = ops->stop;
476 op_str = "Stopping";
477 break;
478 case RPROC_RESET:
479 fn = ops->reset;
480 op_str = "Resetting";
481 break;
482 case RPROC_RUNNING:
483 fn = ops->is_running;
484 op_str = "Checking if running:";
485 break;
486 case RPROC_PING:
487 fn = ops->ping;
488 op_str = "Pinging";
489 break;
490 default:
491 debug("what is '%d' operation??\n", op);
492 return -EINVAL;
493 }
494
495 debug("%s %s...\n", op_str, uc_pdata->name);
496 if (fn)
497 return fn(dev);
498
499 if (mandatory)
500 debug("%s: data corruption?? mandatory function is missing!\n",
501 dev->name);
502
503 return -ENOSYS;
504}
505
506int rproc_start(int id)
507{
508 return _rproc_ops_wrapper(id, RPROC_START);
509};
510
511int rproc_stop(int id)
512{
513 return _rproc_ops_wrapper(id, RPROC_STOP);
514};
515
516int rproc_reset(int id)
517{
518 return _rproc_ops_wrapper(id, RPROC_RESET);
519};
520
521int rproc_ping(int id)
522{
523 return _rproc_ops_wrapper(id, RPROC_PING);
524};
525
526int rproc_is_running(int id)
527{
528 return _rproc_ops_wrapper(id, RPROC_RUNNING);
529};
Keerthy844db202022-01-27 13:16:55 +0100530
Keerthy844db202022-01-27 13:16:55 +0100531static int handle_trace(struct udevice *dev, struct fw_rsc_trace *rsc,
532 int offset, int avail)
533{
534 if (sizeof(*rsc) > avail) {
535 debug("trace rsc is truncated\n");
536 return -EINVAL;
537 }
538
539 /*
540 * make sure reserved bytes are zeroes
541 */
542 if (rsc->reserved) {
543 debug("trace rsc has non zero reserved bytes\n");
544 return -EINVAL;
545 }
546
547 debug("trace rsc: da 0x%x, len 0x%x\n", rsc->da, rsc->len);
548
549 return 0;
550}
551
552static int handle_devmem(struct udevice *dev, struct fw_rsc_devmem *rsc,
553 int offset, int avail)
554{
555 struct rproc_mem_entry *mapping;
556
557 if (sizeof(*rsc) > avail) {
558 debug("devmem rsc is truncated\n");
559 return -EINVAL;
560 }
561
562 /*
563 * make sure reserved bytes are zeroes
564 */
565 if (rsc->reserved) {
566 debug("devmem rsc has non zero reserved bytes\n");
567 return -EINVAL;
568 }
569
570 debug("devmem rsc: pa 0x%x, da 0x%x, len 0x%x\n",
571 rsc->pa, rsc->da, rsc->len);
572
573 rproc_config_pagetable(dev, rsc->da, rsc->pa, rsc->len);
574
575 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
576 if (!mapping)
577 return -ENOMEM;
578
579 /*
580 * We'll need this info later when we'll want to unmap everything
581 * (e.g. on shutdown).
582 *
583 * We can't trust the remote processor not to change the resource
584 * table, so we must maintain this info independently.
585 */
586 mapping->dma = rsc->pa;
587 mapping->da = rsc->da;
588 mapping->len = rsc->len;
589 rproc_add_res(dev, mapping);
590
591 debug("mapped devmem pa 0x%x, da 0x%x, len 0x%x\n",
592 rsc->pa, rsc->da, rsc->len);
593
594 return 0;
595}
596
597static int handle_carveout(struct udevice *dev, struct fw_rsc_carveout *rsc,
598 int offset, int avail)
599{
600 struct rproc_mem_entry *mapping;
601
602 if (sizeof(*rsc) > avail) {
603 debug("carveout rsc is truncated\n");
604 return -EINVAL;
605 }
606
607 /*
608 * make sure reserved bytes are zeroes
609 */
610 if (rsc->reserved) {
611 debug("carveout rsc has non zero reserved bytes\n");
612 return -EINVAL;
613 }
614
615 debug("carveout rsc: da %x, pa %x, len %x, flags %x\n",
616 rsc->da, rsc->pa, rsc->len, rsc->flags);
617
618 rsc->pa = (uintptr_t)rproc_alloc_mem(dev, rsc->len, 8);
619 if (!rsc->pa) {
620 debug
621 ("failed to allocate carveout rsc: da %x, pa %x, len %x, flags %x\n",
622 rsc->da, rsc->pa, rsc->len, rsc->flags);
623 return -ENOMEM;
624 }
625 rproc_config_pagetable(dev, rsc->da, rsc->pa, rsc->len);
626
627 /*
628 * Ok, this is non-standard.
629 *
630 * Sometimes we can't rely on the generic iommu-based DMA API
631 * to dynamically allocate the device address and then set the IOMMU
632 * tables accordingly, because some remote processors might
633 * _require_ us to use hard coded device addresses that their
634 * firmware was compiled with.
635 *
636 * In this case, we must use the IOMMU API directly and map
637 * the memory to the device address as expected by the remote
638 * processor.
639 *
640 * Obviously such remote processor devices should not be configured
641 * to use the iommu-based DMA API: we expect 'dma' to contain the
642 * physical address in this case.
643 */
644 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
645 if (!mapping)
646 return -ENOMEM;
647
648 /*
649 * We'll need this info later when we'll want to unmap
650 * everything (e.g. on shutdown).
651 *
652 * We can't trust the remote processor not to change the
653 * resource table, so we must maintain this info independently.
654 */
655 mapping->dma = rsc->pa;
656 mapping->da = rsc->da;
657 mapping->len = rsc->len;
658 rproc_add_res(dev, mapping);
659
660 debug("carveout mapped 0x%x to 0x%x\n", rsc->da, rsc->pa);
661
662 return 0;
663}
664
665#define RPROC_PAGE_SHIFT 12
666#define RPROC_PAGE_SIZE BIT(RPROC_PAGE_SHIFT)
667#define RPROC_PAGE_ALIGN(x) (((x) + (RPROC_PAGE_SIZE - 1)) & ~(RPROC_PAGE_SIZE - 1))
668
669static int alloc_vring(struct udevice *dev, struct fw_rsc_vdev *rsc, int i)
670{
671 struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
672 int size;
673 int order;
674 void *pa;
675
676 debug("vdev rsc: vring%d: da %x, qsz %d, align %d\n",
677 i, vring->da, vring->num, vring->align);
678
679 /*
680 * verify queue size and vring alignment are sane
681 */
682 if (!vring->num || !vring->align) {
683 debug("invalid qsz (%d) or alignment (%d)\n", vring->num,
684 vring->align);
685 return -EINVAL;
686 }
687
688 /*
689 * actual size of vring (in bytes)
690 */
691 size = RPROC_PAGE_ALIGN(vring_size(vring->num, vring->align));
692 order = vring->align >> RPROC_PAGE_SHIFT;
693
694 pa = rproc_alloc_mem(dev, size, order);
695 if (!pa) {
696 debug("failed to allocate vring rsc\n");
697 return -ENOMEM;
698 }
699 debug("alloc_mem(%#x, %d): %p\n", size, order, pa);
700 vring->da = (uintptr_t)pa;
701
Dan Carpenter21a74062023-07-26 10:00:33 +0300702 return 0;
Keerthy844db202022-01-27 13:16:55 +0100703}
704
705static int handle_vdev(struct udevice *dev, struct fw_rsc_vdev *rsc,
706 int offset, int avail)
707{
708 int i, ret;
709 void *pa;
710
711 /*
712 * make sure resource isn't truncated
713 */
714 if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring)
715 + rsc->config_len > avail) {
716 debug("vdev rsc is truncated\n");
717 return -EINVAL;
718 }
719
720 /*
721 * make sure reserved bytes are zeroes
722 */
723 if (rsc->reserved[0] || rsc->reserved[1]) {
724 debug("vdev rsc has non zero reserved bytes\n");
725 return -EINVAL;
726 }
727
728 debug("vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n",
729 rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings);
730
731 /*
732 * we currently support only two vrings per rvdev
733 */
734 if (rsc->num_of_vrings > 2) {
735 debug("too many vrings: %d\n", rsc->num_of_vrings);
736 return -EINVAL;
737 }
738
739 /*
740 * allocate the vrings
741 */
742 for (i = 0; i < rsc->num_of_vrings; i++) {
743 ret = alloc_vring(dev, rsc, i);
744 if (ret)
745 goto alloc_error;
746 }
747
748 pa = rproc_alloc_mem(dev, RPMSG_TOTAL_BUF_SPACE, 6);
749 if (!pa) {
750 debug("failed to allocate vdev rsc\n");
751 return -ENOMEM;
752 }
753 debug("vring buffer alloc_mem(%#x, 6): %p\n", RPMSG_TOTAL_BUF_SPACE,
754 pa);
755
756 return 0;
757
758 alloc_error:
759 return ret;
760}
761
762/*
763 * A lookup table for resource handlers. The indices are defined in
764 * enum fw_resource_type.
765 */
766static handle_resource_t loading_handlers[RSC_LAST] = {
767 [RSC_CARVEOUT] = (handle_resource_t)handle_carveout,
768 [RSC_DEVMEM] = (handle_resource_t)handle_devmem,
769 [RSC_TRACE] = (handle_resource_t)handle_trace,
770 [RSC_VDEV] = (handle_resource_t)handle_vdev,
771};
772
773/*
774 * handle firmware resource entries before booting the remote processor
775 */
776static int handle_resources(struct udevice *dev, int len,
777 handle_resource_t handlers[RSC_LAST])
778{
779 handle_resource_t handler;
780 int ret = 0, i;
781
782 for (i = 0; i < rsc_table->num; i++) {
783 int offset = rsc_table->offset[i];
784 struct fw_rsc_hdr *hdr = (void *)rsc_table + offset;
785 int avail = len - offset - sizeof(*hdr);
786 void *rsc = (void *)hdr + sizeof(*hdr);
787
788 /*
789 * make sure table isn't truncated
790 */
791 if (avail < 0) {
792 debug("rsc table is truncated\n");
793 return -EINVAL;
794 }
795
796 debug("rsc: type %d\n", hdr->type);
797
798 if (hdr->type >= RSC_LAST) {
799 debug("unsupported resource %d\n", hdr->type);
800 continue;
801 }
802
803 handler = handlers[hdr->type];
804 if (!handler)
805 continue;
806
807 ret = handler(dev, rsc, offset + sizeof(*hdr), avail);
808 if (ret)
809 break;
810 }
811
812 return ret;
813}
814
815static int
816handle_intmem_to_l3_mapping(struct udevice *dev,
817 struct rproc_intmem_to_l3_mapping *l3_mapping)
818{
819 u32 i = 0;
820
821 for (i = 0; i < l3_mapping->num_entries; i++) {
822 struct l3_map *curr_map = &l3_mapping->mappings[i];
823 struct rproc_mem_entry *mapping;
824
825 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
826 if (!mapping)
827 return -ENOMEM;
828
829 mapping->dma = curr_map->l3_addr;
830 mapping->da = curr_map->priv_addr;
831 mapping->len = curr_map->len;
832 rproc_add_res(dev, mapping);
833 }
834
835 return 0;
836}
837
838static Elf32_Shdr *rproc_find_table(unsigned int addr)
839{
840 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
841 Elf32_Shdr *shdr; /* Section header structure pointer */
842 Elf32_Shdr sectionheader;
843 int i;
844 u8 *elf_data;
845 char *name_table;
846 struct resource_table *ptable;
847
848 ehdr = (Elf32_Ehdr *)(uintptr_t)addr;
849 elf_data = (u8 *)ehdr;
850 shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff);
851 memcpy(&sectionheader, &shdr[ehdr->e_shstrndx], sizeof(sectionheader));
852 name_table = (char *)(elf_data + sectionheader.sh_offset);
853
854 for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
855 memcpy(&sectionheader, shdr, sizeof(sectionheader));
856 u32 size = sectionheader.sh_size;
857 u32 offset = sectionheader.sh_offset;
858
859 if (strcmp
860 (name_table + sectionheader.sh_name, ".resource_table"))
861 continue;
862
863 ptable = (struct resource_table *)(elf_data + offset);
864
865 /*
866 * make sure table has at least the header
867 */
868 if (sizeof(struct resource_table) > size) {
869 debug("header-less resource table\n");
870 return NULL;
871 }
872
873 /*
874 * we don't support any version beyond the first
875 */
876 if (ptable->ver != 1) {
877 debug("unsupported fw ver: %d\n", ptable->ver);
878 return NULL;
879 }
880
881 /*
882 * make sure reserved bytes are zeroes
883 */
884 if (ptable->reserved[0] || ptable->reserved[1]) {
885 debug("non zero reserved bytes\n");
886 return NULL;
887 }
888
889 /*
890 * make sure the offsets array isn't truncated
891 */
892 if (ptable->num * sizeof(ptable->offset[0]) +
893 sizeof(struct resource_table) > size) {
894 debug("resource table incomplete\n");
895 return NULL;
896 }
897
898 return shdr;
899 }
900
901 return NULL;
902}
903
904struct resource_table *rproc_find_resource_table(struct udevice *dev,
905 unsigned int addr,
906 int *tablesz)
907{
908 Elf32_Shdr *shdr;
909 Elf32_Shdr sectionheader;
910 struct resource_table *ptable;
911 u8 *elf_data = (u8 *)(uintptr_t)addr;
912
913 shdr = rproc_find_table(addr);
914 if (!shdr) {
915 debug("%s: failed to get resource section header\n", __func__);
916 return NULL;
917 }
918
919 memcpy(&sectionheader, shdr, sizeof(sectionheader));
920 ptable = (struct resource_table *)(elf_data + sectionheader.sh_offset);
921 if (tablesz)
922 *tablesz = sectionheader.sh_size;
923
924 return ptable;
925}
926
927unsigned long rproc_parse_resource_table(struct udevice *dev, struct rproc *cfg)
928{
929 struct resource_table *ptable = NULL;
930 int tablesz;
931 int ret;
932 unsigned long addr;
933
934 addr = cfg->load_addr;
935
936 ptable = rproc_find_resource_table(dev, addr, &tablesz);
937 if (!ptable) {
938 debug("%s : failed to find resource table\n", __func__);
939 return 0;
940 }
941
942 debug("%s : found resource table\n", __func__);
943 rsc_table = kzalloc(tablesz, GFP_KERNEL);
944 if (!rsc_table) {
945 debug("resource table alloc failed!\n");
946 return 0;
947 }
948
949 /*
950 * Copy the resource table into a local buffer before handling the
951 * resource table.
952 */
953 memcpy(rsc_table, ptable, tablesz);
954 if (cfg->intmem_to_l3_mapping)
955 handle_intmem_to_l3_mapping(dev, cfg->intmem_to_l3_mapping);
956 ret = handle_resources(dev, tablesz, loading_handlers);
957 if (ret) {
958 debug("handle_resources failed: %d\n", ret);
959 return 0;
960 }
961
962 /*
963 * Instead of trying to mimic the kernel flow of copying the
964 * processed resource table into its post ELF load location in DDR
965 * copying it into its original location.
966 */
967 memcpy(ptable, rsc_table, tablesz);
968 free(rsc_table);
969 rsc_table = NULL;
970
971 return 1;
972}
MD Danish Anwardb1e4db2024-03-21 15:58:19 +0530973
974int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name)
975{
976 struct dm_rproc_uclass_pdata *uc_pdata;
977 int len;
978 char *p;
979
980 if (!rproc_dev || !fw_name)
981 return -EINVAL;
982
983 uc_pdata = dev_get_uclass_plat(rproc_dev);
984 if (!uc_pdata)
985 return -EINVAL;
986
987 len = strcspn(fw_name, "\n");
988 if (!len) {
989 debug("invalid firmware name\n");
990 return -EINVAL;
991 }
992
993 if (uc_pdata->fw_name)
994 free(uc_pdata->fw_name);
995
996 p = strndup(fw_name, len);
997 if (!p)
998 return -ENOMEM;
999
1000 uc_pdata->fw_name = p;
1001
1002 return 0;
1003}
1004
1005#if CONFIG_IS_ENABLED(FS_LOADER)
1006int rproc_boot(struct udevice *rproc_dev)
1007{
1008 struct dm_rproc_uclass_pdata *uc_pdata;
1009 struct udevice *fs_loader;
1010 int core_id, ret = 0;
1011 char *firmware;
1012 void *addr;
1013
1014 if (!rproc_dev)
1015 return -EINVAL;
1016
1017 uc_pdata = dev_get_uclass_plat(rproc_dev);
1018 if (!uc_pdata)
1019 return -EINVAL;
1020
1021 core_id = dev_seq(rproc_dev);
1022 firmware = uc_pdata->fw_name;
1023 if (!firmware) {
1024 debug("No firmware name set for rproc core %d\n", core_id);
1025 return -EINVAL;
1026 }
1027
1028 /* Initialize all rproc cores */
1029 if (!rproc_is_initialized()) {
1030 ret = rproc_init();
1031 if (ret) {
1032 debug("rproc_init() failed: %d\n", ret);
1033 return ret;
1034 }
1035 }
1036
1037 /* Loading firmware to a given address */
1038 ret = get_fs_loader(&fs_loader);
1039 if (ret) {
1040 debug("could not get fs loader: %d\n", ret);
1041 return ret;
1042 }
1043
1044 if (CONFIG_REMOTEPROC_MAX_FW_SIZE) {
1045 addr = malloc(CONFIG_REMOTEPROC_MAX_FW_SIZE);
1046 if (!addr)
1047 return -ENOMEM;
1048 } else {
1049 debug("CONFIG_REMOTEPROC_MAX_FW_SIZE not defined\n");
1050 return -EINVAL;
1051 }
1052
1053 ret = request_firmware_into_buf(fs_loader, firmware, addr, CONFIG_REMOTEPROC_MAX_FW_SIZE,
1054 0);
1055 if (ret < 0) {
1056 debug("could not request %s: %d\n", firmware, ret);
1057 goto free_buffer;
1058 }
1059
1060 ret = rproc_load(core_id, (ulong)addr, ret);
1061 if (ret) {
1062 debug("failed to load %s to rproc core %d from addr 0x%08lX err %d\n",
1063 uc_pdata->fw_name, core_id, (ulong)addr, ret);
1064 goto free_buffer;
1065 }
1066
1067 ret = rproc_start(core_id);
1068 if (ret)
1069 debug("failed to start rproc core %d\n", core_id);
1070
1071free_buffer:
1072 free(addr);
1073 return ret;
1074}
1075#endif