[PATCH 34.2 3/6] LEON3: add console interrupt mode support
Joel Sherrill
joel.sherrill at OARcorp.com
Wed Apr 18 15:31:40 UTC 2012
Restrictions and warnings like the following really need to
be captured in the Wiki as well.
+ * Note that it is not possible to use the interrupt mode of the driver
+ * together with the "old" APBUART and -u to GRMON. However the new
+ * APBUART core (from GRLIB 1.0.17-b2710) has the GRMON debug bit and can
+ * handle interrupts.
Some method prototypes have a space between the
method name and opening parenthesis. Others do not.
There should not be a space.
Other than that style issue, this looks Ok.
On 04/18/2012 10:19 AM, Daniel Hellstrom wrote:
> The comment in configure.ac is probably inherited from the LEON2
> BSP. The LEON3 console driver implements a "flush" mechanism on
> console_close() in order to solve the problem described with
> sis/LEON2.
>
> Signed-off-by: Daniel Hellstrom<daniel at gaisler.com>
> ---
> c/src/lib/libbsp/sparc/leon3/configure.ac | 5 +-
> c/src/lib/libbsp/sparc/leon3/console/console.c | 164 +++++++++++++++++++++--
> 2 files changed, 150 insertions(+), 19 deletions(-)
>
> diff --git a/c/src/lib/libbsp/sparc/leon3/configure.ac b/c/src/lib/libbsp/sparc/leon3/configure.ac
> index 6d86386..3f2d445 100644
> --- a/c/src/lib/libbsp/sparc/leon3/configure.ac
> +++ b/c/src/lib/libbsp/sparc/leon3/configure.ac
> @@ -26,10 +26,7 @@ RTEMS_BSPOPTS_SET([CONSOLE_USE_INTERRUPTS],[*],[0])
> RTEMS_BSPOPTS_HELP([CONSOLE_USE_INTERRUPTS],
> [The leon3 console driver can operate in either polled or interrupt mode.
> Under the simulator (especially when FAST_UART is defined), polled seems to operate
> -better. It is common for a task to print a line (like the end of test message) and
> -then exit. In this case, the program returns control to the simulator command line
> -before the program has even queued the output to the uart. Thus sis has no chance
> -of getting the data out.])
> +better.])
>
> RTEMS_BSPOPTS_SET([SIMSPARC_FAST_IDLE],[*],[])
> RTEMS_BSPOPTS_HELP([SIMSPARC_FAST_IDLE],
> diff --git a/c/src/lib/libbsp/sparc/leon3/console/console.c b/c/src/lib/libbsp/sparc/leon3/console/console.c
> index 7eafaef..068aced 100644
> --- a/c/src/lib/libbsp/sparc/leon3/console/console.c
> +++ b/c/src/lib/libbsp/sparc/leon3/console/console.c
> @@ -15,6 +15,17 @@
> * http://www.rtems.com/license/LICENSE.
> */
>
> +/* Define CONSOLE_USE_INTERRUPTS to enable APBUART interrupt handling instead
> + * of polling mode.
> + *
> + * Note that it is not possible to use the interrupt mode of the driver
> + * together with the "old" APBUART and -u to GRMON. However the new
> + * APBUART core (from GRLIB 1.0.17-b2710) has the GRMON debug bit and can
> + * handle interrupts.
> + *
> + * NOTE: This can be defined in the make/custom/leon3.cfg file.
> + */
> +
> #include<bsp.h>
> #include<rtems/libio.h>
> #include<stdlib.h>
> @@ -32,12 +43,6 @@
> int syscon_uart_index __attribute__((weak)) = 0;
>
> /*
> - * Should we use a polled or interrupt drived console?
> - *
> - * NOTE: This is defined in the custom/leon.cfg file.
> - */
> -
> -/*
> * apbuart_outbyte_polled
> *
> * This routine transmits a character using polling.
> @@ -63,16 +68,86 @@ extern int apbuart_inbyte_nonblocking(ambapp_apb_uart *regs);
> struct apbuart_priv {
> ambapp_apb_uart *regs;
> unsigned int freq_hz;
> +#if CONSOLE_USE_INTERRUPTS
> + int irq;
> + void *cookie;
> + volatile int sending;
> + char *buf;
> +#endif
> };
> static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
> static int uarts = 0;
>
> +#if CONSOLE_USE_INTERRUPTS
> +
> +/* Handle UART interrupts */
> +void console_isr(void *arg)
> +{
> + struct apbuart_priv *uart = arg;
> + unsigned int status;
> + char data;
> +
> + /* Get all received characters */
> + while ((status=uart->regs->status)& LEON_REG_UART_STATUS_DR) {
> + /* Data has arrived, get new data */
> + data = uart->regs->data;
> +
> + /* Tell termios layer about new character */
> + rtems_termios_enqueue_raw_characters(uart->cookie,&data, 1);
> + }
> +
> + if (status& LEON_REG_UART_STATUS_THE) {
> + /* Sent the one char, we disable TX interrupts */
> + uart->regs->ctrl&= ~LEON_REG_UART_CTRL_TI;
> +
> + /* Tell close that we sent everything */
> + uart->sending = 0;
> +
> + /* write_interrupt will get called from this function */
> + rtems_termios_dequeue_characters(uart->cookie, 1);
> + }
> +}
> +
> +/*
> + * Console Termios Write-Buffer Support Entry Point
> + *
> + */
> +
> +int console_write_interrupt (int minor, const char *buf, int len)
> +{
> + struct apbuart_priv *uart;
> + unsigned int oldLevel;
> +
> + if (minor == 0)
> + uart =&apbuarts[syscon_uart_index];
> + else
> + uart =&apbuarts[minor - 1];
> +
> + /* Remember what position in buffer */
> +
> + rtems_interrupt_disable(oldLevel);
> +
> + /* Enable TX interrupt */
> + uart->regs->ctrl |= LEON_REG_UART_CTRL_TI;
> +
> + /* start UART TX, this will result in an interrupt when done */
> + uart->regs->data = *buf;
> +
> + uart->sending = 1;
> +
> + rtems_interrupt_enable(oldLevel);
> +
> + return 0;
> +}
> +
> +#else
> +
> /*
> * Console Termios Support Entry Points
> *
> */
>
> -ssize_t console_write_support (int minor, const char *buf, size_t len)
> +ssize_t console_write_polled (int minor, const char *buf, size_t len)
> {
> int nwrite = 0, port;
>
> @@ -100,6 +175,8 @@ int console_pollRead(int minor)
> return apbuart_inbyte_nonblocking(apbuarts[port].regs);
> }
>
> +#endif
> +
> int console_set_attributes(int minor, const struct termios *t)
> {
> unsigned int scaler;
> @@ -196,6 +273,9 @@ int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg)
>
> /* Extract needed information of one APBUART */
> apbuarts[uarts].regs = (ambapp_apb_uart *)apb->start;
> +#if CONSOLE_USE_INTERRUPTS
> + apbuarts[uarts].irq = apb->irq;
> +#endif
> /* Get APBUART core frequency, it is assumed that it is the same
> * as Bus frequency where the UART is situated
> */
> @@ -288,35 +368,70 @@ rtems_device_driver console_open(
> )
> {
> rtems_status_code sc;
> - int port;
> + struct apbuart_priv *uart;
> +#if CONSOLE_USE_INTERRUPTS
> + rtems_libio_open_close_args_t *priv = arg;
>
> - static const rtems_termios_callbacks pollCallbacks = {
> + /* Interrupt mode routines */
> + static const rtems_termios_callbacks Callbacks = {
> + NULL, /* firstOpen */
> + NULL, /* lastClose */
> + NULL, /* pollRead */
> + console_write_interrupt, /* write */
> + console_set_attributes, /* setAttributes */
> + NULL, /* stopRemoteTx */
> + NULL, /* startRemoteTx */
> + 1 /* outputUsesInterrupts */
> + };
> +#else
> + /* Polling mode routines */
> + static const rtems_termios_callbacks Callbacks = {
> NULL, /* firstOpen */
> NULL, /* lastClose */
> console_pollRead, /* pollRead */
> - console_write_support, /* write */
> + console_write_polled, /* write */
> console_set_attributes, /* setAttributes */
> NULL, /* stopRemoteTx */
> NULL, /* startRemoteTx */
> 0 /* outputUsesInterrupts */
> };
> +#endif
>
> assert(minor<= uarts);
> if (minor> uarts || minor == (syscon_uart_index + 1))
> return RTEMS_INVALID_NUMBER;
>
> - sc = rtems_termios_open (major, minor, arg,&pollCallbacks);
> + sc = rtems_termios_open (major, minor, arg,&Callbacks);
> if (sc != RTEMS_SUCCESSFUL)
> return sc;
>
> if (minor == 0)
> - port = syscon_uart_index;
> + uart =&apbuarts[syscon_uart_index];
> else
> - port = minor - 1;
> + uart =&apbuarts[minor - 1];
> +
> +#if CONSOLE_USE_INTERRUPTS
> + if (priv&& priv->iop)
> + uart->cookie = priv->iop->data1;
> + else
> + uart->cookie = NULL;
> +
> + /* Register Interrupt handler */
> + sc = rtems_interrupt_handler_install(uart->irq, "console",
> + RTEMS_INTERRUPT_SHARED, console_isr,
> + uart);
> + if (sc != RTEMS_SUCCESSFUL)
> + return sc;
>
> + uart->sending = 0;
> + /* Enable Receiver and transmitter and Turn on RX interrupts */
> + uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE |
> + LEON_REG_UART_CTRL_RI;
> +#else
> /* Initialize UART on opening */
> - apbuarts[port]->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
> - apbuarts[port]->regs->status = 0;
> + uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
> +#endif
> + uart->regs->status = 0;
>
> return RTEMS_SUCCESSFUL;
> }
> @@ -327,6 +442,25 @@ rtems_device_driver console_close(
> void * arg
> )
> {
> +#if CONSOLE_USE_INTERRUPTS
> + struct apbuart_priv *uart;
> +
> + if (minor == 0)
> + uart =&apbuarts[syscon_uart_index];
> + else
> + uart =&apbuarts[minor - 1];
> +
> + /* Turn off RX interrupts */
> + uart->regs->ctrl&= ~(LEON_REG_UART_CTRL_RI);
> +
> + /**** Flush device ****/
> + while (uart->sending) {
> + /* Wait until all data has been sent */
> + }
> +
> + /* uninstall ISR */
> + rtems_interrupt_handler_remove(uart->irq, console_isr, uart);
> +#endif
> return rtems_termios_close (arg);
> }
>
--
Joel Sherrill, Ph.D. Director of Research& Development
joel.sherrill at OARcorp.com On-Line Applications Research
Ask me about RTEMS: a free RTOS Huntsville AL 35805
Support Available (256) 722-9985
More information about the devel
mailing list