mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
serial: sifive: Switch to nbcon console
Add the necessary callbacks(write_atomic, write_thread, device_lock and device_unlock) and CON_NBCON flag to switch the sifive console driver to perform as nbcon console. Both ->write_atomic() and ->write_thread() will check for console ownership whenever they are accessing registers. The ->device_lock()/unlock() will provide the additional serilization necessary for ->write_thread() which is called from dedicated printing thread. Signed-off-by: Ryo Takakura <ryotkkr98@gmail.com> Reviewed-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20250412002544.185038-1-ryotkkr98@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
8bfabff0bf
commit
66f5f70ce0
|
|
@ -141,6 +141,7 @@
|
|||
* @baud_rate: UART serial line rate (e.g., 115200 baud)
|
||||
* @clk: reference to this device's clock
|
||||
* @clk_notifier: clock rate change notifier for upstream clock changes
|
||||
* @console_line_ended: indicate that the console line is fully written
|
||||
*
|
||||
* Configuration data specific to this SiFive UART.
|
||||
*/
|
||||
|
|
@ -151,6 +152,7 @@ struct sifive_serial_port {
|
|||
unsigned long baud_rate;
|
||||
struct clk *clk;
|
||||
struct notifier_block clk_notifier;
|
||||
bool console_line_ended;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -779,33 +781,88 @@ static void sifive_serial_console_putchar(struct uart_port *port, unsigned char
|
|||
|
||||
__ssp_wait_for_xmitr(ssp);
|
||||
__ssp_transmit_char(ssp, ch);
|
||||
|
||||
ssp->console_line_ended = (ch == '\n');
|
||||
}
|
||||
|
||||
static void sifive_serial_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
static void sifive_serial_device_lock(struct console *co, unsigned long *flags)
|
||||
{
|
||||
struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
|
||||
|
||||
__uart_port_lock_irqsave(up, flags);
|
||||
}
|
||||
|
||||
static void sifive_serial_device_unlock(struct console *co, unsigned long flags)
|
||||
{
|
||||
struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
|
||||
|
||||
__uart_port_unlock_irqrestore(up, flags);
|
||||
}
|
||||
|
||||
static void sifive_serial_console_write_atomic(struct console *co,
|
||||
struct nbcon_write_context *wctxt)
|
||||
{
|
||||
struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
|
||||
unsigned long flags;
|
||||
struct uart_port *port = &ssp->port;
|
||||
unsigned int ier;
|
||||
int locked = 1;
|
||||
|
||||
if (!ssp)
|
||||
return;
|
||||
|
||||
if (oops_in_progress)
|
||||
locked = uart_port_trylock_irqsave(&ssp->port, &flags);
|
||||
else
|
||||
uart_port_lock_irqsave(&ssp->port, &flags);
|
||||
if (!nbcon_enter_unsafe(wctxt))
|
||||
return;
|
||||
|
||||
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
|
||||
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
|
||||
|
||||
uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar);
|
||||
if (!ssp->console_line_ended)
|
||||
uart_console_write(port, "\n", 1, sifive_serial_console_putchar);
|
||||
uart_console_write(port, wctxt->outbuf, wctxt->len,
|
||||
sifive_serial_console_putchar);
|
||||
|
||||
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
|
||||
|
||||
if (locked)
|
||||
uart_port_unlock_irqrestore(&ssp->port, flags);
|
||||
nbcon_exit_unsafe(wctxt);
|
||||
}
|
||||
|
||||
static void sifive_serial_console_write_thread(struct console *co,
|
||||
struct nbcon_write_context *wctxt)
|
||||
{
|
||||
struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
|
||||
struct uart_port *port = &ssp->port;
|
||||
unsigned int ier;
|
||||
|
||||
if (!ssp)
|
||||
return;
|
||||
|
||||
if (!nbcon_enter_unsafe(wctxt))
|
||||
return;
|
||||
|
||||
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
|
||||
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
|
||||
|
||||
if (nbcon_exit_unsafe(wctxt)) {
|
||||
int len = READ_ONCE(wctxt->len);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!nbcon_enter_unsafe(wctxt))
|
||||
break;
|
||||
|
||||
uart_console_write(port, wctxt->outbuf + i, 1,
|
||||
sifive_serial_console_putchar);
|
||||
|
||||
if (!nbcon_exit_unsafe(wctxt))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (!nbcon_enter_unsafe(wctxt))
|
||||
nbcon_reacquire_nobuf(wctxt);
|
||||
|
||||
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
|
||||
|
||||
nbcon_exit_unsafe(wctxt);
|
||||
}
|
||||
|
||||
static int sifive_serial_console_setup(struct console *co, char *options)
|
||||
|
|
@ -823,6 +880,8 @@ static int sifive_serial_console_setup(struct console *co, char *options)
|
|||
if (!ssp)
|
||||
return -ENODEV;
|
||||
|
||||
ssp->console_line_ended = true;
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
|
|
@ -833,10 +892,13 @@ static struct uart_driver sifive_serial_uart_driver;
|
|||
|
||||
static struct console sifive_serial_console = {
|
||||
.name = SIFIVE_TTY_PREFIX,
|
||||
.write = sifive_serial_console_write,
|
||||
.write_atomic = sifive_serial_console_write_atomic,
|
||||
.write_thread = sifive_serial_console_write_thread,
|
||||
.device_lock = sifive_serial_device_lock,
|
||||
.device_unlock = sifive_serial_device_unlock,
|
||||
.device = uart_console_device,
|
||||
.setup = sifive_serial_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.flags = CON_PRINTBUFFER | CON_NBCON,
|
||||
.index = -1,
|
||||
.data = &sifive_serial_uart_driver,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user