Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Ryo Takakura and committed by
Greg Kroah-Hartman
66f5f70c 8bfabff0

+75 -13
+75 -13
drivers/tty/serial/sifive.c
··· 141 141 * @baud_rate: UART serial line rate (e.g., 115200 baud) 142 142 * @clk: reference to this device's clock 143 143 * @clk_notifier: clock rate change notifier for upstream clock changes 144 + * @console_line_ended: indicate that the console line is fully written 144 145 * 145 146 * Configuration data specific to this SiFive UART. 146 147 */ ··· 152 151 unsigned long baud_rate; 153 152 struct clk *clk; 154 153 struct notifier_block clk_notifier; 154 + bool console_line_ended; 155 155 }; 156 156 157 157 /* ··· 781 779 782 780 __ssp_wait_for_xmitr(ssp); 783 781 __ssp_transmit_char(ssp, ch); 782 + 783 + ssp->console_line_ended = (ch == '\n'); 784 784 } 785 785 786 - static void sifive_serial_console_write(struct console *co, const char *s, 787 - unsigned int count) 786 + static void sifive_serial_device_lock(struct console *co, unsigned long *flags) 787 + { 788 + struct uart_port *up = &sifive_serial_console_ports[co->index]->port; 789 + 790 + __uart_port_lock_irqsave(up, flags); 791 + } 792 + 793 + static void sifive_serial_device_unlock(struct console *co, unsigned long flags) 794 + { 795 + struct uart_port *up = &sifive_serial_console_ports[co->index]->port; 796 + 797 + __uart_port_unlock_irqrestore(up, flags); 798 + } 799 + 800 + static void sifive_serial_console_write_atomic(struct console *co, 801 + struct nbcon_write_context *wctxt) 788 802 { 789 803 struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index]; 790 - unsigned long flags; 804 + struct uart_port *port = &ssp->port; 791 805 unsigned int ier; 792 - int locked = 1; 793 806 794 807 if (!ssp) 795 808 return; 796 809 797 - if (oops_in_progress) 798 - locked = uart_port_trylock_irqsave(&ssp->port, &flags); 799 - else 800 - uart_port_lock_irqsave(&ssp->port, &flags); 810 + if (!nbcon_enter_unsafe(wctxt)) 811 + return; 801 812 802 813 ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); 803 814 __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); 804 815 805 - uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar); 816 + if (!ssp->console_line_ended) 817 + uart_console_write(port, "\n", 1, sifive_serial_console_putchar); 818 + uart_console_write(port, wctxt->outbuf, wctxt->len, 819 + sifive_serial_console_putchar); 806 820 807 821 __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); 808 822 809 - if (locked) 810 - uart_port_unlock_irqrestore(&ssp->port, flags); 823 + nbcon_exit_unsafe(wctxt); 824 + } 825 + 826 + static void sifive_serial_console_write_thread(struct console *co, 827 + struct nbcon_write_context *wctxt) 828 + { 829 + struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index]; 830 + struct uart_port *port = &ssp->port; 831 + unsigned int ier; 832 + 833 + if (!ssp) 834 + return; 835 + 836 + if (!nbcon_enter_unsafe(wctxt)) 837 + return; 838 + 839 + ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); 840 + __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); 841 + 842 + if (nbcon_exit_unsafe(wctxt)) { 843 + int len = READ_ONCE(wctxt->len); 844 + int i; 845 + 846 + for (i = 0; i < len; i++) { 847 + if (!nbcon_enter_unsafe(wctxt)) 848 + break; 849 + 850 + uart_console_write(port, wctxt->outbuf + i, 1, 851 + sifive_serial_console_putchar); 852 + 853 + if (!nbcon_exit_unsafe(wctxt)) 854 + break; 855 + } 856 + } 857 + 858 + while (!nbcon_enter_unsafe(wctxt)) 859 + nbcon_reacquire_nobuf(wctxt); 860 + 861 + __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); 862 + 863 + nbcon_exit_unsafe(wctxt); 811 864 } 812 865 813 866 static int sifive_serial_console_setup(struct console *co, char *options) ··· 880 823 if (!ssp) 881 824 return -ENODEV; 882 825 826 + ssp->console_line_ended = true; 827 + 883 828 if (options) 884 829 uart_parse_options(options, &baud, &parity, &bits, &flow); 885 830 ··· 892 833 893 834 static struct console sifive_serial_console = { 894 835 .name = SIFIVE_TTY_PREFIX, 895 - .write = sifive_serial_console_write, 836 + .write_atomic = sifive_serial_console_write_atomic, 837 + .write_thread = sifive_serial_console_write_thread, 838 + .device_lock = sifive_serial_device_lock, 839 + .device_unlock = sifive_serial_device_unlock, 896 840 .device = uart_console_device, 897 841 .setup = sifive_serial_console_setup, 898 - .flags = CON_PRINTBUFFER, 842 + .flags = CON_PRINTBUFFER | CON_NBCON, 899 843 .index = -1, 900 844 .data = &sifive_serial_uart_driver, 901 845 };