[PATCH 34.2 3/6] LEON3: add console interrupt mode support

Joel Sherrill joel.sherrill at OARcorp.com
Thu Apr 19 12:19:44 UTC 2012


Ok to commit

Daniel Hellstrom <daniel at gaisler.com> wrote:

>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