LEON3: cleanup console UART indexing handling

The UART indexing was rather a mess when MP was enabled. The changes
introduces two weak variables syscon_uart_index and debug_uart_index
so that the user can override the default system debug console (printk)
and system console UART (/dev/console).

The two weak variables is updated on boot to reflect the "real" UART
index.

MINOR    DEVICE-FS-NAME       UART
0        /dev/console         Default /dev/console_a, user selectable
1        /dev/console_a       APBUART[0]   (missing by default)
2        /dev/console_b       APBUART[1]
...

/dev/console_a is by default renamed /dev/console and assigned minor=0,
but user can select /dev/console_['a'+N] to be renamed to /dev/console
by setting syscon_uart_index=N.

On a MP system the console renamed to /dev/console is selected by CPU
index (LEON3_Cpu_Index). /dev/console_['a' + LEON3_Cpu_Index] is
renamed unless overrided. Resource sharing is performed by the user,
one should not open/access a console that another OS instance uses.

This patch also moves the initialization of the UART to the open()
call, note that before APBUART[0] was always enabled as debug uart
even on MP systems. The debug UART is initialized at boot time.

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
This commit is contained in:
Daniel Hellstrom
2012-04-05 10:23:18 -05:00
committed by Joel Sherrill
parent a36d1b4358
commit 4b557617fd
2 changed files with 125 additions and 60 deletions

View File

@@ -24,6 +24,15 @@
#include <rtems/bspIo.h> #include <rtems/bspIo.h>
#include <amba.h> #include <amba.h>
/* Let user override which on-chip APBUART will be debug UART
* 0 = Default APBUART. On MP system CPU0=APBUART0, CPU1=APBUART1...
* 1 = APBUART[0]
* 2 = APBUART[1]
* 3 = APBUART[2]
* ...
*/
int syscon_uart_index __attribute__((weak)) = 0;
/* /*
* Should we use a polled or interrupt drived console? * Should we use a polled or interrupt drived console?
* *
@@ -44,12 +53,12 @@ void console_outbyte_polled(
/* body is in debugputs.c */ /* body is in debugputs.c */
/* /*
* console_inbyte_nonblocking * apbuart_inbyte_nonblocking
* *
* This routine polls for a character. * This routine polls for a character.
*/ */
int console_inbyte_nonblocking( int port ); int apbuart_inbyte_nonblocking(int port);
/* body is in debugputs.c */ /* body is in debugputs.c */
@@ -61,15 +70,31 @@ int console_inbyte_nonblocking( int port );
ssize_t console_write_support (int minor, const char *buf, size_t len) ssize_t console_write_support (int minor, const char *buf, size_t len)
{ {
int nwrite = 0; int nwrite = 0, port;
if (minor == 0)
port = syscon_uart_index;
else
port = minor - 1;
while (nwrite < len) { while (nwrite < len) {
console_outbyte_polled( minor, *buf++ ); console_outbyte_polled(port, *buf++);
nwrite++; nwrite++;
} }
return nwrite; return nwrite;
} }
int console_inbyte_nonblocking(int minor)
{
int port;
if (minor == 0)
port = syscon_uart_index;
else
port = minor - 1;
return apbuart_inbyte_nonblocking(port);
}
/* /*
* Console Device Driver Entry Points * Console Device Driver Entry Points
@@ -85,45 +110,47 @@ rtems_device_driver console_initialize(
) )
{ {
rtems_status_code status; rtems_status_code status;
int i, uart0; int i;
char console_name[16]; char console_name[16];
rtems_termios_initialize(); rtems_termios_initialize();
/* default console to zero and override if multiprocessing */ /* Update syscon_uart_index to index used as /dev/console
uart0 = 0; * Let user select System console by setting syscon_uart_index. If the
#if defined(RTEMS_MULTIPROCESSING) * BSP is to provide the default UART (syscon_uart_index==0):
if (rtems_configuration_get_user_multiprocessing_table() != NULL) * non-MP: APBUART[0] is system console
uart0 = LEON3_Cpu_Index; * MP: LEON CPU index select UART
#endif */
if (syscon_uart_index == 0) {
#if defined(RTEMS_MULTIPROCESSING)
syscon_uart_index = LEON3_Cpu_Index;
#else
syscon_uart_index = 0;
#endif
} else {
syscon_uart_index = syscon_uart_index - 1; /* User selected sys-console */
}
/* Register Device Names */ /* Register Device Names
if (uarts && (uart0 < uarts)) { *
* 0 /dev/console - APBUART[USER-SELECTED, DEFAULT=APBUART[0]]
* 1 /dev/console_a - APBUART[0] (by default not present because is console)
* 2 /dev/console_b - APBUART[1]
* ...
*
* On a MP system one should not open UARTs that other OS instances use.
*/
if (syscon_uart_index < uarts) {
status = rtems_io_register_name( "/dev/console", major, 0 ); status = rtems_io_register_name( "/dev/console", major, 0 );
if (status != RTEMS_SUCCESSFUL) if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred(status); rtems_fatal_error_occurred(status);
}
strcpy(console_name,"/dev/console_a"); strcpy(console_name,"/dev/console_a");
for (i = uart0+1; i < uarts; i++) { for (i = 0; i < uarts; i++) {
console_name[13]++; if (i == syscon_uart_index)
status = rtems_io_register_name( console_name, major, i); continue; /* skip UART that is registered as /dev/console */
} console_name[13] = 'a' + i;
} status = rtems_io_register_name( console_name, major, i+1);
/*
* Initialize Hardware if ONLY CPU or first CPU in MP system
*/
#if defined(RTEMS_MULTIPROCESSING)
if (rtems_configuration_get_user_multiprocessing_table()->node == 1)
#endif
{
for (i = uart0; i < uarts; i++)
{
LEON3_Console_Uart[i]->ctrl |=
LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
LEON3_Console_Uart[i]->status = 0;
}
} }
return RTEMS_SUCCESSFUL; return RTEMS_SUCCESSFUL;
@@ -136,6 +163,7 @@ rtems_device_driver console_open(
) )
{ {
rtems_status_code sc; rtems_status_code sc;
int port;
static const rtems_termios_callbacks pollCallbacks = { static const rtems_termios_callbacks pollCallbacks = {
NULL, /* firstOpen */ NULL, /* firstOpen */
@@ -148,13 +176,23 @@ rtems_device_driver console_open(
0 /* outputUsesInterrupts */ 0 /* outputUsesInterrupts */
}; };
assert(minor <= uarts);
assert( minor <= LEON3_APBUARTS ); if (minor > uarts || minor == (syscon_uart_index + 1))
if ( minor > LEON3_APBUARTS )
return RTEMS_INVALID_NUMBER; return RTEMS_INVALID_NUMBER;
sc = rtems_termios_open (major, minor, arg, &pollCallbacks); sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
if (sc != RTEMS_SUCCESSFUL)
return sc;
if (minor == 0)
port = syscon_uart_index;
else
port = minor - 1;
/* Initialize UART on opening */
LEON3_Console_Uart[port]->ctrl |= LEON_REG_UART_CTRL_RE |
LEON_REG_UART_CTRL_TE;
LEON3_Console_Uart[port]->status = 0;
return RTEMS_SUCCESSFUL; return RTEMS_SUCCESSFUL;
} }

View File

@@ -7,8 +7,8 @@
* On-Line Applications Research Corporation (OAR). * On-Line Applications Research Corporation (OAR).
* *
* Modified for LEON3 BSP. * Modified for LEON3 BSP.
* COPYRIGHT (c) 2004. * COPYRIGHT (c) 2011.
* Gaisler Research. * Aeroflex Gaisler.
* *
* The license and distribution terms for this file may be * The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at * found in the file LICENSE in this distribution or at
@@ -29,6 +29,15 @@ extern int uarts;
static int isinit = 0; static int isinit = 0;
/* Let user override which on-chip APBUART will be debug UART
* 0 = Default APBUART. On MP system CPU0=APBUART0, CPU1=APBUART1...
* 1 = APBUART[0]
* 2 = APBUART[1]
* 3 = APBUART[2]
* ...
*/
int debug_uart_index __attribute__((weak)) = 0;
/* /*
* Scan for UARTS in configuration * Scan for UARTS in configuration
*/ */
@@ -47,11 +56,27 @@ int scan_uarts(void)
LEON3_Console_Uart[i] = (volatile LEON3_UART_Regs_Map *)apbuarts[i].start; LEON3_Console_Uart[i] = (volatile LEON3_UART_Regs_Map *)apbuarts[i].start;
} }
/* initialize uart 0 if present for printk */ /* Update debug_uart_index to index used as debug console.
if ( uarts ) { * Let user select Debug console by setting debug_uart_index. If the
LEON3_Console_Uart[0]->ctrl |= * BSP is to provide the default UART (debug_uart_index==0):
LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE; * non-MP: APBUART[0] is debug console
LEON3_Console_Uart[0]->status = 0; * MP: LEON CPU index select UART
*/
if (debug_uart_index == 0) {
#if defined(RTEMS_MULTIPROCESSING)
debug_uart_index = LEON3_Cpu_Index;
#else
debug_uart_index = 0;
#endif
} else {
debug_uart_index = debug_uart_index - 1; /* User selected dbg-console */
}
/* initialize debug uart if present for printk */
if (debug_uart_index < uarts) {
LEON3_Console_Uart[debug_uart_index]->ctrl |= LEON_REG_UART_CTRL_RE |
LEON_REG_UART_CTRL_TE;
LEON3_Console_Uart[debug_uart_index]->status = 0;
} }
isinit = 1; isinit = 1;
} }
@@ -70,10 +95,10 @@ void console_outbyte_polled(
) )
{ {
if ((port >= 0) && (port < uarts)) { if ((port >= 0) && (port < uarts)) {
int u = LEON3_Cpu_Index+port; return;
while ( (LEON3_Console_Uart[u]->status & LEON_REG_UART_STATUS_THE) == 0 );
LEON3_Console_Uart[u]->data = (unsigned int) ch; while ( (LEON3_Console_Uart[port]->status & LEON_REG_UART_STATUS_THE) == 0 );
} LEON3_Console_Uart[port]->data = (unsigned int) ch;
} }
/* /*
@@ -81,26 +106,27 @@ void console_outbyte_polled(
* *
* This routine polls for a character. * This routine polls for a character.
*/ */
int console_inbyte_nonblocking( int port ) int apbuart_inbyte_nonblocking(int port)
{ {
if ((port >= 0) && (port < uarts)) { if ((port >= 0) && (port < uarts)) {
int u = LEON3_Cpu_Index+port;
if (LEON3_Console_Uart[u]->status & LEON_REG_UART_STATUS_ERR)
LEON3_Console_Uart[u]->status = ~LEON_REG_UART_STATUS_ERR;
if ((LEON3_Console_Uart[u]->status & LEON_REG_UART_STATUS_DR) == 0)
return -1;
return (int) LEON3_Console_Uart[u]->data;
} else {
assert( 0 ); assert( 0 );
}
return -1; return -1;
}
/* Clear errors */
if (LEON3_Console_Uart[port]->status & LEON_REG_UART_STATUS_ERR)
LEON3_Console_Uart[port]->status = ~LEON_REG_UART_STATUS_ERR;
if ((LEON3_Console_Uart[port]->status & LEON_REG_UART_STATUS_DR) == 0)
return -1;
else
return (int) LEON3_Console_Uart[port]->data;
} }
/* putchar/getchar for printk */ /* putchar/getchar for printk */
static void bsp_out_char(char c) static void bsp_out_char(char c)
{ {
console_outbyte_polled(0, c); console_outbyte_polled(debug_uart_index, c);
} }
/* /*
@@ -115,7 +141,8 @@ static int bsp_in_char(void)
{ {
int tmp; int tmp;
while ((tmp = console_inbyte_nonblocking(0)) < 0); while ((tmp = apbuart_inbyte_nonblocking(debug_uart_index)) < 0)
;
return tmp; return tmp;
} }