On Fri, Dec 27, 2024 at 11:51:21PM +0106, John Ogness wrote: > Implement the necessary callbacks to switch the 8250 console driver > to perform as an nbcon console. > > Add implementations for the nbcon console callbacks: > > ->write_atomic() > ->write_thread() > ->device_lock() > ->device_unlock() > > and add CON_NBCON to the initial @flags. > > All register access in the callbacks are within unsafe sections. > The ->write_atomic and ->write_therad() callbacks allow safe ->write_atomic() > handover/takeover per byte and add a preceding newline if they > take over from another context mid-line. > > For the ->write_atomic() callback, a new irq_work is used to defer > modem control since it may be called from a context that does not > allow waking up tasks. > > Note: A new __serial8250_clear_IER() is introduced for direct > clearing of UART_IER. This will allow to restore the lockdep > check to serial8250_clear_IER() in a follow-up commit. ... > if (toggle_ier) { > + /* > + * Port locked to synchronize UART_IER access > + * against the console Missing period in multi-line comment. > + */ > + lockdep_assert_held_once(&p->port.lock); > + > p->ier |= UART_IER_RLSI | UART_IER_RDI; > serial_port_out(&p->port, UART_IER, p->ier); > } ... > -static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count) > +static int fifo_wait_for_lsr(struct uart_8250_port *up, > + struct nbcon_write_context *wctxt, > + unsigned int count) > { > unsigned int i; > > for (i = 0; i < count; i++) { > + if (!nbcon_can_proceed(wctxt)) > + return -EPERM; > + > if (wait_for_lsr(up, UART_LSR_THRE)) > - return; > + return 0; > } > + > + return -ETIMEDOUT; > } ... > static void serial8250_console_fifo_write(struct uart_8250_port *up, > - const char *s, unsigned int count) > + struct nbcon_write_context *wctxt) > { > - const char *end = s + count; > unsigned int fifosize = up->tx_loadsz; > struct uart_port *port = &up->port; > + const char *s = wctxt->outbuf; > + const char *end = s + wctxt->len; > unsigned int tx_count = 0; > bool cr_sent = false; > unsigned int i; > > while (s != end) { > /* Allow timeout for each byte of a possibly full FIFO */ > - fifo_wait_for_lsr(up, fifosize); > + if (fifo_wait_for_lsr(up, wctxt, fifosize) == -EPERM) > + return; Perhaps it was already discussed and I forgot about it or hadn't read, but I don't get how per-byte check for NBCON permission can help if there is something already in the HW FIFO? I mean in _this_ case wouldn't be enough to check FIFO to drain and only after that check the permission? > for (i = 0; i < fifosize && s != end; ++i) { > if (*s == '\n' && !cr_sent) { > * Allow timeout for each byte written since the caller will only wait > * for UART_LSR_BOTH_EMPTY using the timeout of a single character > */ > - fifo_wait_for_lsr(up, tx_count); > + fifo_wait_for_lsr(up, wctxt, tx_count); > +} ... > + if (up->msr_saved_flags) { > + /* > + * For atomic, it must be deferred to irq_work because this > + * may be a context that does not permit waking up tasks. > + */ > + if (is_atomic) > + irq_work_queue(&up->modem_status_work); > + else > + serial8250_modem_status(up); Hmm... Shouldn't this be part of _modem_status() for all drivers using this call? > + } ... > + bool console_line_ended; /* line fully output */ Sorry, I didn't get the comment. Do you meant "line is fully printed out [to HW]"? -- With Best Regards, Andy Shevchenko