Hi Jiri,

On Mon, Oct 12, 2026 at 8:46 AM Jiri Slaby <[email protected]> wrote:
>
> On 11. 10. 26, 21:55, Magnus Lindholm wrote:
> ...
> > --- /dev/null
> > +++ b/drivers/tty/hvc/hvc_m3000.c
> > @@ -0,0 +1,205 @@
>
> > +struct m3000_console {
> > +     int stdin;
> > +     bool ready;
> > +     u8 buffer[256];
> > +     raw_spinlock_t buffer_lock;
> > +     struct timer_list poll_timer;
> > +     struct mutex poll_mutex; /* Serialize open against synchronous close. 
> > */
> > +     spinlock_t poll_lock; /* Protect active state and timer rearming. */
> > +     bool poll_active;
>
> Perhaps group these a bit better, so that there are not such holes?
>

Done for v3. Reordering the members reduced the structure from 344
to 336 bytes with the tested configuration.

> > +};
> ...
> > +/*
> > + * HVC's idle backoff can exceed the firmware input FIFO's capacity.
> > + * Wake its worker each tick while open; keep PROM calls out of the timer.
> > + */
> > +static void m3000_poll_tick(struct timer_list *timer)
> > +{
> > +     struct m3000_console *con = timer_container_of(con, timer, 
> > poll_timer);
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&con->poll_lock, flags);
>
> Any reason not to use guard()s?
>

No particular reason. I've switched this to guard(spinlock_irqsave).

> > +     if (con->poll_active) {
> > +             hvc_kick();
> > +             mod_timer(&con->poll_timer, jiffies + 1);
> > +     }
> > +     spin_unlock_irqrestore(&con->poll_lock, flags);
> > +}
> > +
> > +static int m3000_open(struct hvc_struct *hp, int data)
> > +{
> > +     struct m3000_console *con = m3000_console(hp->vtermno);
> > +     unsigned long flags;
> > +
> > +     if (!con)
> > +             return -ENODEV;
> > +     mutex_lock(&con->poll_mutex);
> > +     spin_lock_irqsave(&con->poll_lock, flags);
>
> Same here.
>

Done, using guards for both locks, preserving their acquisition and
release order.

> > +     con->poll_active = true;
> > +     mod_timer(&con->poll_timer, jiffies + 1);
> > +     spin_unlock_irqrestore(&con->poll_lock, flags);
> > +     mutex_unlock(&con->poll_mutex);
> > +     return 0;
> > +}
> > +
> > +static void m3000_close(struct hvc_struct *hp, int data)
> > +{
> > +     struct m3000_console *con = m3000_console(hp->vtermno);
> > +     unsigned long flags;
> > +
> > +     if (!con)
> > +             return;
> > +     mutex_lock(&con->poll_mutex);
> > +     spin_lock_irqsave(&con->poll_lock, flags);
>
> And here.
>

Done, using guard(mutex) and a scoped spinlock guard. The spinlock is
released before timer_delete_sync(), while the mutex remains held.

> > +     con->poll_active = false;
> > +     spin_unlock_irqrestore(&con->poll_lock, flags);
> > +     /* Block reopen until the callback has finished and cannot rearm. */
> > +     timer_delete_sync(&con->poll_timer);
> > +     mutex_unlock(&con->poll_mutex);
> > +}
> > +
> > +static ssize_t m3000_io(struct m3000_console *con, u8 *in,
> > +                     const u8 *out, size_t count)
> > +{
> > +     unsigned long args[7], flags;
> > +     bool input = in;
>
> You can test "in" below directly, right?
>

Yes, I've removed the boolean and now test "in" directly.

> > +     int ret;
> > +
> > +     if (!count)
> > +             return 0;
> > +     count = min(count, input ? 1 : sizeof(con->buffer));
> > +     /* Console writes can run with interrupts disabled; this lock cannot 
> > sleep. */
> > +     raw_spin_lock_irqsave(&con->buffer_lock, flags);
>
> scoped_guard()
>

Done for v3. Reordering the members reduced the structure from 344
to 336 bytes with the tested configuration.

> > +     if (!input)
> > +             memcpy(con->buffer, out, count);
> > +     args[0] = (unsigned long)(input ? "read" : "write");
> > +     args[1] = 3;
> > +     args[2] = 1;
> > +     args[3] = (unsigned int)(input ? con->stdin : prom_stdout);
> > +     args[4] = (unsigned long)con->buffer;
> > +     args[5] = count;
> > +     args[6] = (unsigned long)-1;
> > +     p1275_cmd_direct(args);
> > +     ret = (int)args[6];
> > +     if (ret > 0 && ret <= count && input)
> > +             memcpy(in, con->buffer, ret);
> > +     raw_spin_unlock_irqrestore(&con->buffer_lock, flags);
> > +     if (ret == -2 || ret == 0)
>
> That's full of magic constants. Can we have defines for those?
>

I've added defines for the firmware argument/return counts and the
-1/-2 status values. I've kept zero literal as a zero-byte result.

> > +             return 0;
> > +     if (ret < 0 || ret > count)
> > +             return -EIO;
> > +     return ret;
> thanks,
> --
> js
> suse labs

Both GCC and Clang W=1 builds completed, and the GCC-built kernel
passed boot and HVC input/output, open/close, and hangup/reopen tests
on the M3000.

I'll put out the v3 asap

Regards,
Magnus

Reply via email to