[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