Re: [PATCH] drm/mipi-dsi: Reduce driver bloat of mipi_dsi_*_write_seq()

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

 



Hi,

On Thu, Apr 25, 2024 at 1:19 AM Jani Nikula <jani.nikula@xxxxxxxxxxxxxxx> wrote:
>
> > @@ -279,6 +281,8 @@ enum mipi_dsi_dcs_tear_mode {
> >
> >  ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
> >                                 const void *data, size_t len);
> > +ssize_t mipi_dsi_dcs_write_buffer_chatty(struct mipi_dsi_device *dsi,
> > +                                      const void *data, size_t len);
> >  ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
> >                          const void *data, size_t len);
> >  ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
> > @@ -317,14 +321,10 @@ int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi,
> >  #define mipi_dsi_generic_write_seq(dsi, seq...)                                \
> >       do {                                                                   \
> >               static const u8 d[] = { seq };                                 \
> > -             struct device *dev = &dsi->dev;                                \
> >               int ret;                                                       \
> > -             ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));           \
> > -             if (ret < 0) {                                                 \
> > -                     dev_err_ratelimited(dev, "transmit data failed: %d\n", \
> > -                                         ret);                              \
> > +             ret = mipi_dsi_generic_write_chatty(dsi, d, ARRAY_SIZE(d));    \
> > +             if (ret < 0)                                                   \
> >                       return ret;                                            \
> > -             }                                                              \
> >       } while (0)
>
> The one thing that I've always disliked about these macros (even if I've
> never actually used them myself) is that they hide control flow from the
> caller, i.e. return directly. You don't see that in the code, it's not
> documented, and if you wanted to do better error handling yourself,
> you're out of luck.

Yeah, I agree that it's not the cleanest. That being said, it is
existing code and making the existing code less bloated seems worth
doing.

I'd also say that it feels worth it to have _some_ solution so that
the caller doesn't need to write error handling after every single cmd
sent. If we get rid of / discourage these macros that's either going
to end us up with ugly/verbose code or it's going to encourage people
to totally skip error handling. IMO neither of those are wonderful
solutions.

While thinking about this there were a few ideas I came up with. None
of them are amazing, but probably they are better than the hidden
"return" like this. Perhaps we could mark the current function as
"deprecated" and pick one of these depending on what others opinions
are:

1. Use "goto" and force the caller to give a goto target for error handling.

This is based on an idea that Dmitry came up with, but made a little
more explicit. Example usage:

int ret;

ret = 0;
mipi_dsi_dcs_write_seq_goto(dsi, &ret, HX83102_SETSPCCMD, 0xcd,
                            some_cmd_failed);
mipi_dsi_dcs_write_seq_goto(dsi, &ret, HX83102_SETMIPI, 0x84,
                            some_cmd_failed);
mipi_dsi_dcs_write_seq_goto(dsi, &ret, HX83102_SETSPCCMD, 0x3f,
                            some_cmd_failed);
mipi_dsi_dcs_write_seq_goto(dsi, &ret, HX83102_SETVDC, 0x1b, 0x04,
                            some_cmd_failed);

...

some_cmd_failed:
  pr_err("Commands failed to write: %d", ret);
  return ret;
}

One downside here is that you can't easily tell which command failed
to put it in the error message. A variant of this idea (1a?) could be
to hoist the print back into the write command. I'd want to pick one
or the other. I guess my preference would be to hoist the print into
the write command and if someone really doesn't want the print then
they call mipi_dsi_dcs_write_buffer() directly.

---

2. Accept that a slightly less efficient handling of the error case
and perhaps a less intuitive API, but avoid the goto.

Essentially you could pass in "ret" and have the function be a no-op
if an error is already present. Something like this:

void mipi_dsi_dcs_write_buffer_multi(struct mipi_dsi_device *dsi,
const void *data, size_t len, int *accum_ret)
{
  if (*accum_ret)
    return;

  *accum_ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
}

...and then the caller:

int ret;

ret = 0;
mipi_dsi_dcs_write_seq_multi(dsi, HX83102_SETSPCCMD, 0xcd, &ret);
mipi_dsi_dcs_write_seq_multi(dsi, HX83102_SETMIPI, 0x84, &ret);
mipi_dsi_dcs_write_seq_multi(dsi, HX83102_SETSPCCMD, 0x3f, &ret);
mipi_dsi_dcs_write_seq_multi(dsi, HX83102_SETVDC, 0x1b, 0x04, &ret);
if (ret)
  goto some_cmd_failed;

This has similar properties to solution #1.

---

3. Accept that callers don't want to error handling but just need a print.

I'm not 100% sure we want to encourage this. On the one hand it's
unlikely anyone is really going to be able to reliably recover super
properly from an error midway through a big long command sequence. On
the other hand, this means we can't pass the error back to the caller.
In theory the caller _could_ try to handle errors by resetting / power
cycling things, so that's a real downside.

Example usage:

mipi_dsi_dcs_write_seq_chatty(dsi, HX83102_SETSPCCMD, 0xcd);
mipi_dsi_dcs_write_seq_chatty(dsi, HX83102_SETMIPI, 0x84);
mipi_dsi_dcs_write_seq_chatty(dsi, HX83102_SETSPCCMD, 0x3f);
mipi_dsi_dcs_write_seq_chatty(dsi, HX83102_SETVDC, 0x1b, 0x04);

---

I think I'd lean towards #1a (user passes goto label and we include
the error print in the helper), but I'd personally be happy with any
of #1 or #2. I don't love #3.

> Be that as it may, the combo of ratelimited error printing and return on
> errors does not make much sense to me. If there's something to print,
> you bail out, that's it. I suspect we never hit the ratelimit.

Yeah, I'm in favor of removing the ratelimit.


> You might even want to try *only* changing the ratelimited printing to a
> regular error message, and see if the compiler can combine the logging
> to a single exit point in the callers. Ratelimited it obviously can't
> because every single one of them is unique.

It wasn't quite as good. Comparing the "after" solution (AKA applying
$SUBJECT patch) vs. _not_ taking $SUBJECT patch and instead changing
dev_err_ratelimited() to dev_err().

$ scripts/bloat-o-meter \
   .../after/panel-novatek-nt36672e.ko \
  .../noratelimit/panel-novatek-nt36672e.ko
add/remove: 0/0 grow/shrink: 1/0 up/down: 3404/0 (3404)
Function                                     old     new   delta
nt36672e_1080x2408_60hz_init                7260   10664   +3404
Total: Before=11669, After=15073, chg +29.17%

...so $SUBJECT patch is still better.

---

Where does that leave us? IMO:

a) If others agree, we should land $SUBJECT patch. It doesn't change
the behavior at all and gives big savings. It adds an extra function
hop, but presumably the fact that we have to fetch _a lot_ less stuff
from RAM might mean we still get better performance (likely it doesn't
matter anyway since this is not hotpath code).

b) Atop this patch, we should consider changing dev_err_ratelimited()
to dev_err(). It doesn't seem to make lots of sense to me to ratelimit
this error.

c) Atop this patch, we should consider making the two existing macros
"deprecated" in favor of a new macro that makes the control flow more
obvious.

How does that sound to folks?

-Doug




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux