From: Roger Quadros <rogerq@kernel.org>
To: "Anwar, Md Danish" <a0501179@ti.com>,
MD Danish Anwar <danishanwar@ti.com>,
Max Krummenacher <max.krummenacher@toradex.com>,
Francesco Dolcini <francesco.dolcini@toradex.com>,
Dan Carpenter <dan.carpenter@linaro.org>,
Simon Glass <sjg@chromium.org>, Nishanth Menon <nm@ti.com>,
Tom Rini <trini@konsulko.com>
Cc: u-boot@lists.denx.de, srk@ti.com,
Vignesh Raghavendra <vigneshr@ti.com>,
r-gunasekaran@ti.com
Subject: Re: [PATCH v4] remoteproc: uclass: Add methods to load firmware to rproc and boot rproc
Date: Mon, 5 Feb 2024 12:06:29 +0200 [thread overview]
Message-ID: <d0b4530d-b12a-4b2c-8171-35ca003d4234@kernel.org> (raw)
In-Reply-To: <8bc580b4-5faf-48f4-9d68-052fb9e114e8@ti.com>
On 02/02/2024 18:40, Anwar, Md Danish wrote:
> Hi Roger,
>
> On 2/2/2024 4:49 PM, Roger Quadros wrote:
>>
>>
>> On 30/01/2024 08:33, MD Danish Anwar wrote:
>>> Add APIs to set a firmware_name to a rproc and boot the rproc with the
>>> same firmware.
>>>
>>> Clients can call rproc_set_firmware() API to set firmware_name for a rproc
>>> whereas rproc_boot() will load the firmware set by rproc_set_firmware() to
>>> a buffer by calling request_firmware_into_buf(). rproc_boot() will then
>>> load the firmware file to the remote processor and start the remote
>>> processor.
>>>
>>> Also include "fs-loader.h" and make remoteproc driver select FS_LOADER in
>>> Kconfig so that we can call request_firmware_into_buf() from remoteproc
>>> driver.
>>>
>>> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
>>> ---
>>> Changes from v3 to v4:
>>> *) No functional change. Splitted the patch out of the series as suggested
>>> by Nishant.
>>> *) Droppped the RFC tag.
>>>
>>> v3: https://lore.kernel.org/all/20240124064930.1787929-4-danishanwar@ti.com/
>>>
>>> drivers/remoteproc/Kconfig | 1 +
>>> drivers/remoteproc/rproc-uclass.c | 85 +++++++++++++++++++++++++++++++
>>> include/remoteproc.h | 35 +++++++++++++
>>> 3 files changed, 121 insertions(+)
>>>
>>> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
>>> index 781de530af..0fdf1b38ea 100644
>>> --- a/drivers/remoteproc/Kconfig
>>> +++ b/drivers/remoteproc/Kconfig
>>> @@ -10,6 +10,7 @@ menu "Remote Processor drivers"
>>> # All users should depend on DM
>>> config REMOTEPROC
>>> bool
>>> + select FS_LOADER
>>> depends on DM
>>>
>>> # Please keep the configuration alphabetically sorted.
>>> diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c
>>> index 28b362c887..76db4157f7 100644
>>> --- a/drivers/remoteproc/rproc-uclass.c
>>> +++ b/drivers/remoteproc/rproc-uclass.c
>>> @@ -13,6 +13,7 @@
>>> #include <log.h>
>>> #include <malloc.h>
>>> #include <virtio_ring.h>
>>> +#include <fs_loader.h>
>>> #include <remoteproc.h>
>>> #include <asm/io.h>
>>> #include <dm/device-internal.h>
>>> @@ -961,3 +962,87 @@ unsigned long rproc_parse_resource_table(struct udevice *dev, struct rproc *cfg)
>>>
>>> return 1;
>>> }
>>> +
>>> +int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name)
>>> +{
>>> + struct dm_rproc_uclass_pdata *uc_pdata;
>>> + int len;
>>> + char *p;
>>> +
>>> + if (!rproc_dev || !fw_name)
>>> + return -EINVAL;
>>> +
>>> + uc_pdata = dev_get_uclass_plat(rproc_dev);
>>
>> This can return NULL and you shuould error out if it does.
>>
>
> Sure.
>
>>> +
>>> + len = strcspn(fw_name, "\n");
>>> + if (!len) {
>>> + debug("can't provide empty string for firmware name\n");
>>
>> how about "invalid filename" ?
>>
>
> Sure.
>
>>> + return -EINVAL;
>>> + }
>>> +
>>> + p = strndup(fw_name, len);
>>> + if (!p)
>>> + return -ENOMEM;
>>> +
>>> + uc_pdata->fw_name = p;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +int rproc_boot(struct udevice *rproc_dev, size_t fw_size)
>>> +{
>>> + struct dm_rproc_uclass_pdata *uc_pdata;
>>> + struct udevice *fs_loader;
>>> + void *addr = malloc(fw_size);
>>
>> I will suggest to do malloc just before you need the buffer.
>> You need to free up the buffer an all return paths after that.
>>
>
> That is correct. I will do malloc just before calling
> request_firmware_into_buf() API.
>
>>> + int core_id, ret = 0;
>>> + char *firmware;
>>> + ulong rproc_addr;
>>
>> do you really need rproc_addr? You could use addr itself.
>>
>
> Sure.
>
>>> +
>>> + if (!rproc_dev)
>>> + return -EINVAL;
>>> +
>>> + if (!addr)
>>> + return -ENOMEM;
>>> +
>>> + uc_pdata = dev_get_uclass_plat(rproc_dev);
>>> + core_id = dev_seq(rproc_dev);
>>> + firmware = uc_pdata->fw_name;
>>> +
>>> + if (!firmware) {
>>> + debug("No firmware set for rproc core %d\n", core_id);
>>> + return -EINVAL;
>>> + }
>>> +
>>> + /* Initialize all rproc cores */
>>> + rproc_init();
>>
>> if (!rproc_is_initialized()) {
>> ret = rproc_init()
>> if (ret) {
>> debug("rproc_init() failed: %d\n", ret);
>> return ret;
>> }
>> }
>>
>
> Sure.
>
>>> +
>>> + /* Loading firmware to a given address */
>>> + ret = get_fs_loader(&fs_loader);
>>> + if (ret) {
>>> + debug("could not get fs loader: %d\n", ret);
>>> + return ret;
>>> + }
>>> +
>>> + ret = request_firmware_into_buf(fs_loader, firmware, addr, fw_size, 0);
>>> + if (ret < 0) {
>>> + debug("could not request %s: %d\n", firmware, ret);
>>> + return ret;
>>> + }
>>> +
>>> + rproc_addr = (ulong)addr;
>>> +
>>> + ret = rproc_load(core_id, rproc_addr, ret);
>>
>> ret = rproc_load(coare_id, (ulong)addr, ret);
>>
>>> + if (ret) {
>>> + debug("failed to load %s to rproc core %d from addr 0x%08lX err %d\n",
>>> + uc_pdata->fw_name, core_id, rproc_addr, ret);
>>> + return ret;
>>> + }
>>> +
>>> + ret = rproc_start(core_id);
>>> + if (ret) {
>>> + debug("failed to start rproc core %d\n", core_id);
>>> + return ret;
>>> + }
>>> +
>>> + return ret;
>>
>> return 0;
>>
>>> +}
>>> diff --git a/include/remoteproc.h b/include/remoteproc.h
>>> index 91a88791a4..e53f85ba51 100644
>>> --- a/include/remoteproc.h
>>> +++ b/include/remoteproc.h
>>> @@ -403,6 +403,7 @@ enum rproc_mem_type {
>>> * @name: Platform-specific way of naming the Remote proc
>>> * @mem_type: one of 'enum rproc_mem_type'
>>> * @driver_plat_data: driver specific platform data that may be needed.
>>> + * @fw_name: firmware name
>>> *
>>> * This can be accessed with dev_get_uclass_plat() for any UCLASS_REMOTEPROC
>>> * device.
>>> @@ -412,6 +413,7 @@ struct dm_rproc_uclass_pdata {
>>> const char *name;
>>> enum rproc_mem_type mem_type;
>>> void *driver_plat_data;
>>> + char *fw_name;
>>> };
>>>
>>> /**
>>> @@ -705,6 +707,35 @@ unsigned long rproc_parse_resource_table(struct udevice *dev,
>>> struct resource_table *rproc_find_resource_table(struct udevice *dev,
>>> unsigned int addr,
>>> int *tablesz);
>>> +/**
>>> + * rproc_set_firmware() - assign a new firmware
>>
>> firmware/firmware name.
>>
>>> + * @rproc_dev: device for wich new firmware is being assigned
>>
>> firmware/firmware name
>> wich/which
>>
>>> + * @fw_name: new firmware name to be assigned
>>> + *
>>> + * This function allows remoteproc drivers or clients to configure a custom
>>> + * firmware name. The function does not trigger a remote processor boot,
>>> + * only sets the firmware name used for a subsequent boot.
>>> + *
>>> + * This function sets the fw_name field in uclass pdata of the Remote proc
>>> + *
>>> + * Return: 0 on success or a negative value upon failure
>>> + */
>>> +int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name);
>>> +
>>> +/**
>>> + * rproc_boot() - boot a remote processor
>>> + * @rproc_dev: rproc device to boot
>>> + * @fw_size: Size of the memory to allocate for firmeware
>>
>> firmeware/firmware
>>
>
> I'll fix all these typos.
>
>> How does caller know what firmware size to set to?
>> This should already be private to the rproc as it knows
>> how large is its program memory.
>>
>
> Caller is trying to boot the rproc with a firmware binary. Caller should
> know the size of binary that it wants to load to rproc core. Caller will
> specify the binary size to rproc_boot(). Based on the size provided by
> caller, rproc_boot() will then allocate that much memory and call
> request_firmware_into_buf() with the size and allocated buffer. If the
> caller doesn't provide minimum size rproc_load() will fail.
Caller only knows the filename. It need not know more details.
Also see my comment below about rproc_boot() API.
>
> rproc_load() calls respective driver ops, for example: pru_load().
> pru_load() [1] API checks the required size of firmware to load by
> casting the buffer into Elf32_Ehdr and Elf32_Phdr and returns error if
> size provided by caller is less than this.
>
>
> if (offset + filesz > size) {
> dev_dbg(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> offset + filesz, size);
> ret = -EINVAL;
> break;
> }
>
>>> + *
>>> + * Boot a remote processor (i.e. load its firmware, power it on, ...).
>>> + *
>>> + * This function first loads the firmware set in the uclass pdata of Remote
>>> + * processor to a buffer and then loads firmware to the remote processor
>>> + * using rproc_load().
>>> + *
>>> + * Return: 0 on success, and an appropriate error value otherwise
>>> + */
>>> +int rproc_boot(struct udevice *rproc_dev, size_t fw_size);
>>
>> Was wondering if you need separate API for rproc_set_firmware or we can just
>> pass firmware name as argument to rproc_boot()?
>>
>
> Technically we can. But when we discussed this approach first in v1, you
> had asked to keep the APIs similar to upstream linux. Upstream linux has
> these two APIs so I kept it that way. If you want I can drop the first
> API. Please let me know.
Sure you can keep it as it is in Linux, but there, rproc_boot doesn't
take fw_size argument. So wondering why you should have it in u-boot.
>
>>> #else
>>> static inline int rproc_init(void) { return -ENOSYS; }
>>> static inline int rproc_dev_init(int id) { return -ENOSYS; }
>>> @@ -744,6 +775,10 @@ static inline int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
>>> ulong fw_size, ulong *rsc_addr,
>>> ulong *rsc_size)
>>> { return -ENOSYS; }
>>> +static inline int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name)
>>> +{ return -ENOSYS; }
>>> +static inline int rproc_boot(struct udevice *rproc_dev, size_t fw_size)
>>> +{ return -ENOSYS; }
>>> #endif
>>>
>>> #endif /* _RPROC_H_ */
>>
>
> [1]
> https://elixir.bootlin.com/u-boot/latest/source/drivers/remoteproc/pru_rproc.c#L324
>
--
cheers,
-roger
next prev parent reply other threads:[~2024-02-05 10:06 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-30 6:33 [PATCH v4] remoteproc: uclass: Add methods to load firmware to rproc and boot rproc MD Danish Anwar
2024-02-02 7:51 ` Ravi Gunasekaran
2024-02-02 11:19 ` Roger Quadros
2024-02-02 16:40 ` Anwar, Md Danish
2024-02-05 10:06 ` Roger Quadros [this message]
2024-02-05 10:20 ` MD Danish Anwar
2024-02-05 12:37 ` Roger Quadros
2024-02-06 5:31 ` MD Danish Anwar
2024-02-06 13:41 ` Roger Quadros
2024-02-07 7:15 ` MD Danish Anwar
2024-02-07 12:35 ` Roger Quadros
2024-02-07 12:57 ` Anwar, Md Danish
2024-02-09 9:15 ` MD Danish Anwar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=d0b4530d-b12a-4b2c-8171-35ca003d4234@kernel.org \
--to=rogerq@kernel.org \
--cc=a0501179@ti.com \
--cc=dan.carpenter@linaro.org \
--cc=danishanwar@ti.com \
--cc=francesco.dolcini@toradex.com \
--cc=max.krummenacher@toradex.com \
--cc=nm@ti.com \
--cc=r-gunasekaran@ti.com \
--cc=sjg@chromium.org \
--cc=srk@ti.com \
--cc=trini@konsulko.com \
--cc=u-boot@lists.denx.de \
--cc=vigneshr@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox