On Thu, Sep 30, 2021 at 09:29:03AM +0300, Tony Lindgren wrote: > If the serial driver implements PM runtime with autosuspend, the port may > be powered down on TX. To wake up the port, let's add new wakeup() call > for serial drivers to implement as needed. We can call wakeup() from > __uart_start() and flow control related functions before attempting to > write to the serial port registers. > > Let's keep track of the serial port with a new runtime_suspended flag > that the device driver runtime PM suspend and resume can manage with > atomic_set(). This is because only the device driver knows what the > device runtime PM state as in Documentation/power/runtime_pm.rst > under "9. Autosuspend, or automatically-delayed suspend" for locking. > > To allow the serial port drivers to send out pending tx on runtime PM > resume, let's add start_pending_tx() as suggested by Johan Hovold > <johan@xxxxxxxxxx>. > > Suggested-by: Johan Hovold <johan@xxxxxxxxxx> > Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx> > --- > Documentation/driver-api/serial/driver.rst | 9 ++++ > drivers/tty/serial/serial_core.c | 56 +++++++++++++++++++++- > include/linux/serial_core.h | 3 ++ > 3 files changed, 66 insertions(+), 2 deletions(-) > > diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst > --- a/Documentation/driver-api/serial/driver.rst > +++ b/Documentation/driver-api/serial/driver.rst > @@ -234,6 +234,15 @@ hardware. > > Interrupts: caller dependent. > > + wakeup(port) > + Wake up port if it has been runtime PM suspended. > + > + Locking: port->lock taken. > + > + Interrupts: locally disabled. > + > + This call must not sleep > + > flush_buffer(port) > Flush any write buffers, reset any DMA state and stop any > ongoing DMA transfers. > diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c > --- a/drivers/tty/serial/serial_core.c > +++ b/drivers/tty/serial/serial_core.c > @@ -91,6 +91,23 @@ static inline struct uart_port *uart_port_check(struct uart_state *state) > return state->uart_port; > } > > +/* > + * This routine can be used before register access to wake up a serial > + * port that has been runtime PM suspended by the serial port driver. > + * Note that the runtime_suspended flag is managed by the serial port > + * device driver runtime PM. > + */ > +static int uart_port_wakeup(struct uart_port *port) > +{ > + if (!atomic_read(&port->runtime_suspended)) > + return 0; And if the value changes right after you read this? Why not use a real lock here? Don't use an atomic if you don't need it. thanks, greg k-h