RE: [RESENT PATCH v3 1/5] mmc-utils: Refactor common FFU code into functions to support additional FFU modes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> On Mon, 2024-10-21 at 07:39 +0000, Avri Altman wrote:
> > > > > +               return -ENOMEM;
> > > > > +       }
> > > > I was expecting that do_ffu_download will be called with struct
> > > > mmc_ioc_multi_cmd *multi_cmd argument as well.
> > > > That each ffu<x> mode fills it according to its own logic.
> > > > This you won't be needing that ffu_mode additional parameter.
> > >
> > > I wanted to clarify why the ffu_mode parameter is necessary during
> > > the download phase. By extracting the logic into a common approach
> > > and using ffu_mode to dynamically update the multi_cmd structure
> > > across iterations per ffu-mode, I can handle the variations between
> > > different FFU modes more effectively. This allows me to extract more
> > > common code and avoid duplication, as the ffu_mode helps determine
> > > which specific updates or adjustments need to be made to the
> > > multi_cmd at each stage.
> > >
> > > Without this, it would be difficult to manage multiple loops or
> > > iterations of the download process, especially when the command
> > > structure needs to be modified in different ways depending on the
> > > mode.
> > > The use of ffu_mode centralizes this control, making the code
> > > cleaner and more maintainable.
> > I see your point.
> > Each mode is packing differently the multi-ioctl, and you need to
> > update different offset of the cmds part.
> > So how about instead of ffu mode, adjust set_ffu_single_cmd to do just
> > that.
> >
> > And maybe in few preparation phases - to make the review process more
> > concise:
> > First let's make it get the cmds part of the multi-ioctl instead of
> > the multi-ioctl:
> > +static void set_ffu_write_cmd(struct mmc_ioc_cmd *cmds, __u8
> > *ext_csd, unsigned int bytes,
> > +                             __u8 *buf, off_t offset)
> >  {
> >         __u32 arg = per_byte_htole32(&ext_csd[EXT_CSD_FFU_ARG_0]);
> >
> >         /* send block count */
> > -       set_single_cmd(&multi_cmd->cmds[1], MMC_SET_BLOCK_COUNT, 0,
> > 0,
> > -                      bytes / 512);
> > -       multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
> > MMC_CMD_AC;
> > +       set_single_cmd(&cmds[0], MMC_SET_BLOCK_COUNT, 0, 0, bytes /
> > 512);
> > +       cmds[0].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
> >
> >         /*
> >          * send image chunk: blksz and blocks essentially do not
> > matter, as
> >          * long as the product is fw_size, but some hosts don't handle
> > larger
> >          * blksz well.
> >          */
> > -       set_single_cmd(&multi_cmd->cmds[2],
> MMC_WRITE_MULTIPLE_BLOCK,
> > 1,
> > -                      bytes / 512, arg);
> > -       mmc_ioc_cmd_set_data(multi_cmd->cmds[2], buf + offset);
> > +       set_single_cmd(&cmds[1], MMC_WRITE_MULTIPLE_BLOCK, 1, bytes /
> > 512, arg);
> > +       mmc_ioc_cmd_set_data(cmds[1], buf + offset); }
> >
> > And then, allow it to carry sbc or not:
> > +static void set_ffu_sbc_cmd(struct mmc_ioc_cmd *cmds, int bytes)
> >  {
> > -       __u32 arg = per_byte_htole32(&ext_csd[EXT_CSD_FFU_ARG_0]);
> > -
> >         /* send block count */
> > -       set_single_cmd(&multi_cmd->cmds[1], MMC_SET_BLOCK_COUNT, 0,
> > 0,
> > -                      bytes / 512);
> > -       multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
> > MMC_CMD_AC;
> > +       set_single_cmd(&cmds[0], MMC_SET_BLOCK_COUNT, 0, 0, bytes /
> > 512);
> > +       cmds[0].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; }
> >
> > +static void set_ffu_write_cmd(struct mmc_ioc_cmd *cmds, __u8
> > *ext_csd, unsigned int bytes,
> > +                             __u8 *buf, off_t offset, bool sbc) {
> > +       __u32 arg = per_byte_htole32(&ext_csd[EXT_CSD_FFU_ARG_0]);
> > +
> > +       if (sbc)
> > +               set_ffu_sbc_cmd(cmds, bytes);
> >         /*
> >          * send image chunk: blksz and blocks essentially do not
> > matter, as
> >          * long as the product is fw_size, but some hosts don't handle
> > larger
> >          * blksz well.
> >          */
> > -       set_single_cmd(&multi_cmd->cmds[2],
> MMC_WRITE_MULTIPLE_BLOCK,
> > 1,
> > -                      bytes / 512, arg);
> > -       mmc_ioc_cmd_set_data(multi_cmd->cmds[2], buf + offset);
> > +       set_single_cmd(&cmds[1], MMC_WRITE_MULTIPLE_BLOCK, 1, bytes /
> > 512, arg);
> > +       mmc_ioc_cmd_set_data(cmds[1], buf + offset); }
> > +
> >
> > And only then, as a 3rd preparation phase move the do_retry out.
> > And you need to tell it what offset the write commands are.  I guess
> > this is the equivalent of your ffu_mode.
> > But the difference is that when I look into do_ffu2, do_ffu3 etc. -
> > The logic of pointing to the write command is there.
> >
> > +static int __do_ffu(int dev_fd, char *device, struct
> > mmc_ioc_multi_cmd *multi_cmd, int cmd_off,
> > +                   off_t fw_size, unsigned int sect_size, unsigned
> > int default_chunk,
> > +                   __u8 *ext_csd, __u8 *buf)
> > Maybe we can pack all the ffu arguments into a single control struct
> > to get passed to __do_ffu as struct ffu_params *.
> >
> > +{
> > +       off_t bytes_left, off;
> > +       __u32 sect_done = 0;
> > +       __u8 ffu_feature = ext_csd[EXT_CSD_FFU_FEATURES];
> > +       int write_command_offset = cmd_off;
> > +       int retry = 3;
> > +       int ret;
> > +
> > +do_retry:
> > +       bytes_left = fw_size;
> > +       off = 0;
> > +       while (bytes_left) {
> > +               unsigned int chunk_size = bytes_left < default_chunk
> > ?
> > +                                         bytes_left : default_chunk;
> > +
> > +               /* prepare multi_cmd for FFU based on cmd to be used
> > */
> > +               set_ffu_write_cmd(&multi_cmd-
> > >cmds[write_command_offset],
> > +                                       ext_csd, chunk_size, buf,
> > off, 1);
> > +
> > +               /* send ioctl with multi-cmd */
> > +               ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);
> > +               if (ret) {
> > +                       perror("Multi-cmd ioctl");
> > +                       /*
> > +                        * In case multi-cmd ioctl failed before
> > exiting from
> > +                        * ffu mode
> > +                        */
> > +                       ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd-
> > >cmds[3]);
> > +                       return ret;
> > +               }
> > +
> > +               bytes_left -= chunk_size;
> > +               off += chunk_size;
> > +       }
> > +
> > +       /*
> > +        * By spec - check if mode operation codes are supported in
> > ffu features,
> > +        * if not then skip checking number of sectors programmed
> > after install
> > +        */
> > +       if (!ffu_feature) {
> > +               fprintf(stderr, "Please reboot to complete firmware
> > installation on %s\n", device);
> > +               return 0;
> > +       }
> > +
> > +       ret = read_extcsd(dev_fd, ext_csd);
> > +       if (ret) {
> > +               fprintf(stderr, "Could not read EXT_CSD from %s\n",
> > device);
> > +               return ret;
> > +       }
> > +
> > +       /* Test if we need to restart the download */
> > +       sect_done =
> > per_byte_htole32(&ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_0]);
> > +       /* By spec, host should re-start download from the first
> > sector if sect_done is 0 */
> > +       if (sect_done == 0) {
> > +               if (retry--) {
> > +                       fprintf(stderr, "Programming failed.
> > Retrying... (%d)\n", retry);
> > +                       goto do_retry;
> > +               }
> > +               fprintf(stderr, "Programming failed! Aborting...\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       fprintf(stderr, "Programmed %jd/%jd bytes\n",
> > (intmax_t)sect_done * sect_size, (intmax_t)fw_size);
> > +
> > +       if ((sect_done * sect_size) == fw_size) {
> > +               fprintf(stderr, "Programming finished
> > successfully\n");
> > +               return 0;
> > +       }
> > +
> > +       fprintf(stderr, "FW size and number of sectors written
> > mismatch\n");
> > +       return -EINVAL;
> >  }
> >
> > Each mode can have its own arguments - it’s a different de-facto util
> > so you are not bounded by do_ffu arguments.
> > Thus the argument parsing is done for each mode differently.
> > Also allocating the multi-ioctl is privet to each mode.  Some have 4,
> > some have 2, and some 1.
> >
> > Thanks,
> > Avri
> 
> I can change your suggestions, before changing, I would like to have a solid
> agreement,
> 
> 
> The approach in my patch is to concentrate differences in
> do_ffu_download() while keeping common functions outside it, the reason
> for this becuase the main difference btw ffu_modes are FW budnle
> download.
> 
> void _do_ffu(int ffu_mode) {
> 
>    // Declare parameters specific to the FFU mode
>     do_ffu_prepare();
>     ffu_is_supported();
> 
>     do_ffu_download(ffu_mode);
> 
>     do_ffu_installation();
> }
> 
> void do_ffu1() {
>     _do_ffu(FFU_MODE_1);
> }
> 
> void do_ffu2() {
>     _do_ffu(FFU_MODE_2);
> }
> 
> 
> Advantages:
> 
> Reduced Duplication: Each do_ffu<x>() avoids repeating the same logic.
> Improved Maintainability: Changes only need to be made in one location.
> Clear Separation: Common operations remain consistent across all modes.
> 
> 
> The approach you suggested is to sperate them at the begigning of
> do_ffu<x>, then pass the different parameters to each different
> function:
> 
> It risks unnecessary duplication and increased complexity, as seen in this
> structure:
> 
> void do_ffu1() {
>     // Duplicate logic here
>     do_ffu_prepare(ffu1);
>     ffu_is_supported();
>     do_ffu_download(ffu_structure);
>     do_ffu_installation();
> }
> 
> void do_ffu2() {
>     // Duplicate logic here
>     do_ffu_prepare(ffu2);
>     ffu_is_supported();
>     do_ffu_download(ffu_structure);
>     do_ffu_installation();
> }
> 
> Please tell me was the second one what you expected?
I see that you still think that the ffu_mode is better.
I don't want to block the progress of the series - as I am aware that there are customers that are waiting.
Please feel free to add my Acked-by tag to the whole series.

Thanks,
Avri

> 
> 
> Kind regards,
> Bean




[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux