Skip to content

Commit 70acca6

Browse files
esbengregkh
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fd29e1e commit 70acca6

File tree

1 file changed

+101
-19
lines changed

1 file changed

+101
-19
lines changed

drivers/tty/serial/imx.c

Lines changed: 101 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ struct imx_port {
230230
unsigned int saved_reg[10];
231231
bool context_saved;
232232

233+
bool last_putchar_was_newline;
234+
233235
enum imx_tx_state tx_state;
234236
struct hrtimer trigger_start_tx;
235237
struct hrtimer trigger_stop_tx;
@@ -2064,26 +2066,34 @@ static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch)
20642066
barrier();
20652067

20662068
imx_uart_writel(sport, ch, URTX0);
2069+
2070+
sport->last_putchar_was_newline = (ch == '\n');
20672071
}
20682072

2069-
/*
2070-
* Interrupts are disabled on entering
2071-
*/
2072-
static void
2073-
imx_uart_console_write(struct console *co, const char *s, unsigned int count)
2073+
static void imx_uart_console_device_lock(struct console *co, unsigned long *flags)
2074+
{
2075+
struct uart_port *up = &imx_uart_ports[co->index]->port;
2076+
2077+
return __uart_port_lock_irqsave(up, flags);
2078+
}
2079+
2080+
static void imx_uart_console_device_unlock(struct console *co, unsigned long flags)
2081+
{
2082+
struct uart_port *up = &imx_uart_ports[co->index]->port;
2083+
2084+
return __uart_port_unlock_irqrestore(up, flags);
2085+
}
2086+
2087+
static void imx_uart_console_write_atomic(struct console *co,
2088+
struct nbcon_write_context *wctxt)
20742089
{
20752090
struct imx_port *sport = imx_uart_ports[co->index];
2091+
struct uart_port *port = &sport->port;
20762092
struct imx_port_ucrs old_ucr;
2077-
unsigned long flags;
20782093
unsigned int ucr1, usr2;
2079-
int locked = 1;
20802094

2081-
if (sport->port.sysrq)
2082-
locked = 0;
2083-
else if (oops_in_progress)
2084-
locked = uart_port_trylock_irqsave(&sport->port, &flags);
2085-
else
2086-
uart_port_lock_irqsave(&sport->port, &flags);
2095+
if (!nbcon_enter_unsafe(wctxt))
2096+
return;
20872097

20882098
/*
20892099
* First, save UCR1/2/3 and then disable interrupts
@@ -2097,10 +2107,12 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
20972107
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN);
20982108

20992109
imx_uart_writel(sport, ucr1, UCR1);
2100-
21012110
imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2);
21022111

2103-
uart_console_write(&sport->port, s, count, imx_uart_console_putchar);
2112+
if (!sport->last_putchar_was_newline)
2113+
uart_console_write(port, "\n", 1, imx_uart_console_putchar);
2114+
uart_console_write(port, wctxt->outbuf, wctxt->len,
2115+
imx_uart_console_putchar);
21042116

21052117
/*
21062118
* Finally, wait for transmitter to become empty
@@ -2110,8 +2122,73 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
21102122
0, USEC_PER_SEC, false, sport, USR2);
21112123
imx_uart_ucrs_restore(sport, &old_ucr);
21122124

2113-
if (locked)
2114-
uart_port_unlock_irqrestore(&sport->port, flags);
2125+
nbcon_exit_unsafe(wctxt);
2126+
}
2127+
2128+
static void imx_uart_console_write_thread(struct console *co,
2129+
struct nbcon_write_context *wctxt)
2130+
{
2131+
struct imx_port *sport = imx_uart_ports[co->index];
2132+
struct uart_port *port = &sport->port;
2133+
struct imx_port_ucrs old_ucr;
2134+
unsigned int ucr1, usr2;
2135+
2136+
if (!nbcon_enter_unsafe(wctxt))
2137+
return;
2138+
2139+
/*
2140+
* First, save UCR1/2/3 and then disable interrupts
2141+
*/
2142+
imx_uart_ucrs_save(sport, &old_ucr);
2143+
ucr1 = old_ucr.ucr1;
2144+
2145+
if (imx_uart_is_imx1(sport))
2146+
ucr1 |= IMX1_UCR1_UARTCLKEN;
2147+
ucr1 |= UCR1_UARTEN;
2148+
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN);
2149+
2150+
imx_uart_writel(sport, ucr1, UCR1);
2151+
imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2);
2152+
2153+
if (nbcon_exit_unsafe(wctxt)) {
2154+
int len = READ_ONCE(wctxt->len);
2155+
int i;
2156+
2157+
/*
2158+
* Write out the message. Toggle unsafe for each byte in order
2159+
* to give another (higher priority) context the opportunity
2160+
* for a friendly takeover. If such a takeover occurs, this
2161+
* context must reacquire ownership in order to perform final
2162+
* actions (such as re-enabling the interrupts).
2163+
*
2164+
* IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid
2165+
* after a reacquire so writing the message must be
2166+
* aborted.
2167+
*/
2168+
for (i = 0; i < len; i++) {
2169+
if (!nbcon_enter_unsafe(wctxt))
2170+
break;
2171+
2172+
uart_console_write(port, wctxt->outbuf + i, 1,
2173+
imx_uart_console_putchar);
2174+
2175+
if (!nbcon_exit_unsafe(wctxt))
2176+
break;
2177+
}
2178+
}
2179+
2180+
while (!nbcon_enter_unsafe(wctxt))
2181+
nbcon_reacquire_nobuf(wctxt);
2182+
2183+
/*
2184+
* Finally, wait for transmitter to become empty
2185+
* and restore UCR1/2/3
2186+
*/
2187+
read_poll_timeout(imx_uart_readl, usr2, usr2 & USR2_TXDC,
2188+
0, USEC_PER_SEC, false, sport, USR2);
2189+
imx_uart_ucrs_restore(sport, &old_ucr);
2190+
2191+
nbcon_exit_unsafe(wctxt);
21152192
}
21162193

21172194
/*
@@ -2203,6 +2280,8 @@ imx_uart_console_setup(struct console *co, char *options)
22032280
if (retval)
22042281
goto error_console;
22052282

2283+
sport->last_putchar_was_newline = true;
2284+
22062285
if (options)
22072286
uart_parse_options(options, &baud, &parity, &bits, &flow);
22082287
else
@@ -2239,11 +2318,14 @@ imx_uart_console_exit(struct console *co)
22392318
static struct uart_driver imx_uart_uart_driver;
22402319
static struct console imx_uart_console = {
22412320
.name = DEV_NAME,
2242-
.write = imx_uart_console_write,
2321+
.write_atomic = imx_uart_console_write_atomic,
2322+
.write_thread = imx_uart_console_write_thread,
2323+
.device_lock = imx_uart_console_device_lock,
2324+
.device_unlock = imx_uart_console_device_unlock,
2325+
.flags = CON_PRINTBUFFER | CON_NBCON,
22432326
.device = uart_console_device,
22442327
.setup = imx_uart_console_setup,
22452328
.exit = imx_uart_console_exit,
2246-
.flags = CON_PRINTBUFFER,
22472329
.index = -1,
22482330
.data = &imx_uart_uart_driver,
22492331
};

0 commit comments

Comments
 (0)