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: imx: Switch to nbcon console

Implements the necessary callbacks to switch the imx console driver to
perform as an nbcon console.

Add implementations for the nbcon consoles (write_atomic, write_thread,
driver_enter, driver_exit) and add CON_NBCON to the initial flags.

The legacy code is kept in order to easily switch back to legacy mode
by defining CONFIG_SERIAL_IMX_LEGACY_CONSOLE.

Signed-off-by: Esben Haabendal <esben@geanix.com>
Link: https://lore.kernel.org/r/20240913-serial-imx-nbcon-v3-1-4c627302335b@geanix.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Esben Haabendal and committed by
Greg Kroah-Hartman
70acca67 fd29e1e4

+101 -19
+101 -19
drivers/tty/serial/imx.c
··· 230 230 unsigned int saved_reg[10]; 231 231 bool context_saved; 232 232 233 + bool last_putchar_was_newline; 234 + 233 235 enum imx_tx_state tx_state; 234 236 struct hrtimer trigger_start_tx; 235 237 struct hrtimer trigger_stop_tx; ··· 2066 2064 barrier(); 2067 2065 2068 2066 imx_uart_writel(sport, ch, URTX0); 2067 + 2068 + sport->last_putchar_was_newline = (ch == '\n'); 2069 2069 } 2070 2070 2071 - /* 2072 - * Interrupts are disabled on entering 2073 - */ 2074 - static void 2075 - imx_uart_console_write(struct console *co, const char *s, unsigned int count) 2071 + static void imx_uart_console_device_lock(struct console *co, unsigned long *flags) 2072 + { 2073 + struct uart_port *up = &imx_uart_ports[co->index]->port; 2074 + 2075 + return __uart_port_lock_irqsave(up, flags); 2076 + } 2077 + 2078 + static void imx_uart_console_device_unlock(struct console *co, unsigned long flags) 2079 + { 2080 + struct uart_port *up = &imx_uart_ports[co->index]->port; 2081 + 2082 + return __uart_port_unlock_irqrestore(up, flags); 2083 + } 2084 + 2085 + static void imx_uart_console_write_atomic(struct console *co, 2086 + struct nbcon_write_context *wctxt) 2076 2087 { 2077 2088 struct imx_port *sport = imx_uart_ports[co->index]; 2089 + struct uart_port *port = &sport->port; 2078 2090 struct imx_port_ucrs old_ucr; 2079 - unsigned long flags; 2080 2091 unsigned int ucr1, usr2; 2081 - int locked = 1; 2082 2092 2083 - if (sport->port.sysrq) 2084 - locked = 0; 2085 - else if (oops_in_progress) 2086 - locked = uart_port_trylock_irqsave(&sport->port, &flags); 2087 - else 2088 - uart_port_lock_irqsave(&sport->port, &flags); 2093 + if (!nbcon_enter_unsafe(wctxt)) 2094 + return; 2089 2095 2090 2096 /* 2091 2097 * First, save UCR1/2/3 and then disable interrupts ··· 2107 2097 ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); 2108 2098 2109 2099 imx_uart_writel(sport, ucr1, UCR1); 2110 - 2111 2100 imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); 2112 2101 2113 - uart_console_write(&sport->port, s, count, imx_uart_console_putchar); 2102 + if (!sport->last_putchar_was_newline) 2103 + uart_console_write(port, "\n", 1, imx_uart_console_putchar); 2104 + uart_console_write(port, wctxt->outbuf, wctxt->len, 2105 + imx_uart_console_putchar); 2114 2106 2115 2107 /* 2116 2108 * Finally, wait for transmitter to become empty ··· 2122 2110 0, USEC_PER_SEC, false, sport, USR2); 2123 2111 imx_uart_ucrs_restore(sport, &old_ucr); 2124 2112 2125 - if (locked) 2126 - uart_port_unlock_irqrestore(&sport->port, flags); 2113 + nbcon_exit_unsafe(wctxt); 2114 + } 2115 + 2116 + static void imx_uart_console_write_thread(struct console *co, 2117 + struct nbcon_write_context *wctxt) 2118 + { 2119 + struct imx_port *sport = imx_uart_ports[co->index]; 2120 + struct uart_port *port = &sport->port; 2121 + struct imx_port_ucrs old_ucr; 2122 + unsigned int ucr1, usr2; 2123 + 2124 + if (!nbcon_enter_unsafe(wctxt)) 2125 + return; 2126 + 2127 + /* 2128 + * First, save UCR1/2/3 and then disable interrupts 2129 + */ 2130 + imx_uart_ucrs_save(sport, &old_ucr); 2131 + ucr1 = old_ucr.ucr1; 2132 + 2133 + if (imx_uart_is_imx1(sport)) 2134 + ucr1 |= IMX1_UCR1_UARTCLKEN; 2135 + ucr1 |= UCR1_UARTEN; 2136 + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); 2137 + 2138 + imx_uart_writel(sport, ucr1, UCR1); 2139 + imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); 2140 + 2141 + if (nbcon_exit_unsafe(wctxt)) { 2142 + int len = READ_ONCE(wctxt->len); 2143 + int i; 2144 + 2145 + /* 2146 + * Write out the message. Toggle unsafe for each byte in order 2147 + * to give another (higher priority) context the opportunity 2148 + * for a friendly takeover. If such a takeover occurs, this 2149 + * context must reacquire ownership in order to perform final 2150 + * actions (such as re-enabling the interrupts). 2151 + * 2152 + * IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid 2153 + * after a reacquire so writing the message must be 2154 + * aborted. 2155 + */ 2156 + for (i = 0; i < len; i++) { 2157 + if (!nbcon_enter_unsafe(wctxt)) 2158 + break; 2159 + 2160 + uart_console_write(port, wctxt->outbuf + i, 1, 2161 + imx_uart_console_putchar); 2162 + 2163 + if (!nbcon_exit_unsafe(wctxt)) 2164 + break; 2165 + } 2166 + } 2167 + 2168 + while (!nbcon_enter_unsafe(wctxt)) 2169 + nbcon_reacquire_nobuf(wctxt); 2170 + 2171 + /* 2172 + * Finally, wait for transmitter to become empty 2173 + * and restore UCR1/2/3 2174 + */ 2175 + read_poll_timeout(imx_uart_readl, usr2, usr2 & USR2_TXDC, 2176 + 0, USEC_PER_SEC, false, sport, USR2); 2177 + imx_uart_ucrs_restore(sport, &old_ucr); 2178 + 2179 + nbcon_exit_unsafe(wctxt); 2127 2180 } 2128 2181 2129 2182 /* ··· 2280 2203 if (retval) 2281 2204 goto error_console; 2282 2205 2206 + sport->last_putchar_was_newline = true; 2207 + 2283 2208 if (options) 2284 2209 uart_parse_options(options, &baud, &parity, &bits, &flow); 2285 2210 else ··· 2318 2239 static struct uart_driver imx_uart_uart_driver; 2319 2240 static struct console imx_uart_console = { 2320 2241 .name = DEV_NAME, 2321 - .write = imx_uart_console_write, 2242 + .write_atomic = imx_uart_console_write_atomic, 2243 + .write_thread = imx_uart_console_write_thread, 2244 + .device_lock = imx_uart_console_device_lock, 2245 + .device_unlock = imx_uart_console_device_unlock, 2246 + .flags = CON_PRINTBUFFER | CON_NBCON, 2322 2247 .device = uart_console_device, 2323 2248 .setup = imx_uart_console_setup, 2324 2249 .exit = imx_uart_console_exit, 2325 - .flags = CON_PRINTBUFFER, 2326 2250 .index = -1, 2327 2251 .data = &imx_uart_uart_driver, 2328 2252 };