Re: [PATCH v3] hw/char/pl011: support backend hotswap

Alexander Mikhalitsyn <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <CAJqdLrpdp1mfFU9ci62z4Ck29o9LMAbCOgq22xdCBvezkrov4g@mail.gmail.com>
Am Fr., 21. Aug. 2026 um 11:57 Uhr schrieb Peter Maydell
<[email protected]>:
>
> On Mon, 17 Aug 2026 at 12:33, Alexander Mikhalitsyn
> <[email protected]> wrote:
> >
> > From: Alexander Mikhalitsyn <[email protected]>
> >
> > Currently, when Incus issues "chardev-change" QMP command to change
> > chardev backend from ringbuf to socket it receives an error (with aarch64 VM):
> > "Chardev user does not support chardev hotswap" [1], [2]
> >
> > Let's fix this by properly implementing BackendChangeHandler for pl011.
> >
> > Please, note that we have to "replay" CHR_IOCTL_SERIAL_SET_BREAK, because
> > if BRK bit was set before backend change (i.e. (s->lcr & LCR_BRK) is true),
> > then after change we need to send break to a new backend too.
> >
> > Link: https://discuss.linuxcontainers.org/t/unable-to-connect-to-vm-console-on-arm-architecture/23096/3 [1]
> > Link: https://github.com/lxc/distrobuilder/issues/892 [2]
> > Reported-by: Stéphane Graber <[email protected]>
> > Reviewed-by: Alex Bennée <[email protected]>
> > Signed-off-by: Alexander Mikhalitsyn <[email protected]>
> > ---
> > v3:
> >         - introduced pl011_set_handlers()
> >           [ as suggested by Alex Bennée ]
> >         - introduced pl011_set_break()
> >           [ as suggested by Philippe Mathieu-Daudé ]
> > v2:
> >         - fixed a typo in commit author name
> >           [ I did `git format-patch` and copied this patch from my Raspberry PI
> >             dev/test machine and it turns out that I have a stupid typo in my
> >             `git config get user.name` on that machine. ]
> >         - added RWB tag from Alex Bennée
> >         - adjusted a commit message
>
> I have one review suggestion here:
>
> > +static inline int pl011_set_break(PL011State *s, uint64_t lcr)
> > +{
> > +    int break_enable = lcr & LCR_BRK;
> > +
> > +    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &break_enable);
> > +
> > +    return break_enable;
> > +}
>
> I think this would be better with a similar API to
> pl011_loopback_break(): make it take a bool brk_enable,
> and return void. (pl011_loopback_break() takes an int,
> but we shouldn't copy that: it uses it as a bool, so it
> ought to take a bool.)

Dear Peter,

Sure, I've changed this ;-) The only thing is that I kept brk_enable
as int, because in serial_chr_ioctl we have:
static int serial_chr_ioctl(Chardev *chr, int cmd, void *arg)
{
<...>
    case CHR_IOCTL_SERIAL_SET_BREAK:
        {
            int enable = *(int *)arg; // << int is assumed
            if (enable) {
                tcsendbreak(fioc->fd, 1);
            }
        }

I'll send -v4 in a moment.

Kind regards,
Alex

>
> >  static void pl011_write(void *opaque, hwaddr offset,
> >                          uint64_t value, unsigned size)
> >  {
> > @@ -462,9 +471,7 @@ static void pl011_write(void *opaque, hwaddr offset,
> >              pl011_reset_tx_fifo(s);
> >          }
> >          if ((s->lcr ^ value) & LCR_BRK) {
> > -            int break_enable = value & LCR_BRK;
> > -            qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
> > -                              &break_enable);
> > +            int break_enable = pl011_set_break(s, value);
> >              pl011_loopback_break(s, break_enable);
>
> Then this code becomes something like
>     bool break_enable = value & LCR_BRK;
>     pl011_set_break(s, break_enable);
>     pl011_loopback_break(s, break_enable);
>
> which is more straightforward than passing the raw LCR value
> to pl011_set_break and relying on it returning the "is BRK set?"
> information that we then pass to pl011_loopback_break().

+

>
> > +static int pl011_be_change(void *opaque);
>
> > +static inline void pl011_set_handlers(PL011State *s)
> > +{
> > +    qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
> > +                             pl011_event, pl011_be_change, s, NULL, true);
> > +}
> > +
> > +static int pl011_be_change(void *opaque)
> > +{
> > +    PL011State *s = opaque;
> > +
> > +    pl011_set_handlers(s);
> > +    pl011_set_break(s, s->lcr);
>
> and here we would then pass in s->lcr & LCR_BRK.

+

>
> > +
> > +    return 0;
> > +}
>
> thanks
> -- PMM
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.