[PATCH 34.2 3/6] LEON3: add console interrupt mode support
Daniel Hellstrom
daniel at gaisler.com
Thu Apr 19 09:20:27 UTC 2012
On 04/18/2012 05:31 PM, Joel Sherrill wrote:
> 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.
Ok, I will update the patch. I have added some text to the LEON3 BSP wiki as well. Thanks.
>
> 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);
>> }
>>
>
>
More information about the devel
mailing list