Hi all, I applied 'patch-2.6.31.4-rt14' patch from www.kernel.org on 2.6.31 kernel from buserror repo and I got an issue with serial port. When I try to connect to my mini2440 using serial cable linux works very slowly and there is a process [irq/71-s3c2440-] (serial port irq) which eats about 80-90% of CPU. Moreover, when I work on the board over SSH everything is fine and I can work quit comfortably. Could please anybody say how can I resolve this issue? Thanks!
ttySAC0 issue on 2.6.31 after real time patch
I got some free time and dug into problem with ttySAC0 console. I applied patch-2.6.31.5 and patch-2.6.31.5-rt18 on 2.6.31 linux kernel from Buserror repo and after tracing kernel console function calls I realised that the reason why linux works so slowly on console is busy loop on 71 interrupt rising ([irq/71-s3c2440-] process). Loop was on s3c24xx_serial_tx_chars function calling with empty output buffer (uart_circ_empty(xmit) == 1) that caused calling s3c24xx_serial_stop_tx function with tx_enabled(port) parameter equals to 0 (without calling disable_irq_nosync). This function is a handler of tx_irq for ttySAC0 uart. Thus, at some moment IRQ rised and never cleaned that caused busy loop. My solution was replacing spin_lock_irqsave and spin_unlock_irqrestore functions in drivers/serial/samsung.c and /drivers/serial/serial_core.c files with their 'atomic' analogs (atomic_spin_lock_irqsave and atomic_spin_unlock_irqrestore). Below I posted patch as temporary workaround for this issue: --- a/drivers/serial/samsung.c 2009-10-07 19:48:09.000000000 +0300 +++ b/drivers/serial/samsung.c 2009-11-09 11:11:57.000000000 +0200 @@ -90,7 +90,7 @@ unsigned int ucon, ufcon; int count = 10000; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); while (--count && !s3c24xx_serial_txempty_nofifo(port)) udelay(100); @@ -104,7 +104,7 @@ wr_regl(port, S3C2410_UCON, ucon); rx_enabled(port) = 1; - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } static void s3c24xx_serial_rx_disable(struct uart_port *port) @@ -112,14 +112,14 @@ unsigned long flags; unsigned int ucon; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); ucon = rd_regl(port, S3C2410_UCON); ucon &= ~S3C2410_UCON_RXIRQMODE; wr_regl(port, S3C2410_UCON, ucon); rx_enabled(port) = 0; - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } static void s3c24xx_serial_stop_tx(struct uart_port *port) @@ -359,7 +359,7 @@ unsigned long flags; unsigned int ucon; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); ucon = rd_regl(port, S3C2410_UCON); @@ -370,7 +370,7 @@ wr_regl(port, S3C2410_UCON, ucon); - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } static void s3c24xx_serial_shutdown(struct uart_port *port) @@ -746,7 +746,7 @@ ulcon |= S3C2410_LCON_PNONE; } - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n", ulcon, quot, udivslot); @@ -790,7 +790,7 @@ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= RXSTAT_DUMMY_READ; - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } static const char *s3c24xx_serial_type(struct uart_port *port) --- a/drivers/serial/serial_core.c 2009-10-07 19:48:09.000000000 +0300 +++ b/drivers/serial/serial_core.c 2009-11-09 11:16:56.000000000 +0200 @@ -86,9 +86,9 @@ struct uart_port *port = state->port; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); port->ops->stop_tx(port); - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } static void __uart_start(struct tty_struct *tty) @@ -107,9 +107,9 @@ struct uart_port *port = state->port; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); __uart_start(tty); - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } static void uart_tasklet_action(unsigned long data) @@ -124,12 +124,12 @@ unsigned long flags; unsigned int old; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); old = port->mctrl; port->mctrl = (old & ~clear) | set; if (old != port->mctrl) port->ops->set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } #define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) @@ -190,10 +190,10 @@ } if (info->flags & UIF_CTS_FLOW) { - spin_lock_irq(&port->lock); + atomic_spin_lock_irq(&port->lock); if (!(port->ops->get_mctrl(port) & TIOCM_CTS)) info->port.tty->hw_stopped = 1; - spin_unlock_irq(&port->lock); + atomic_spin_unlock_irq(&port->lock); } info->flags |= UIF_INITIALIZED; @@ -468,13 +468,13 @@ if (!circ->buf) return 0; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); if (uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); ret = 1; } - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); return ret; } @@ -514,7 +514,7 @@ if (!circ->buf) return 0; - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); while (1) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); if (count < c) @@ -527,7 +527,7 @@ count -= c; ret += c; } - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); uart_start(tty); return ret; @@ -539,9 +539,9 @@ unsigned long flags; int ret; - spin_lock_irqsave(&state->port->lock, flags); + atomic_spin_lock_irqsave(&state->port->lock, flags); ret = uart_circ_chars_free(&state->info.xmit); - spin_unlock_irqrestore(&state->port->lock, flags); + atomic_spin_unlock_irqrestore(&state->port->lock, flags); return ret; } @@ -551,9 +551,9 @@ unsigned long flags; int ret; - spin_lock_irqsave(&state->port->lock, flags); + atomic_spin_lock_irqsave(&state->port->lock, flags); ret = uart_circ_chars_pending(&state->info.xmit); - spin_unlock_irqrestore(&state->port->lock, flags); + atomic_spin_unlock_irqrestore(&state->port->lock, flags); return ret; } @@ -575,11 +575,11 @@ port = state->port; pr_debug("uart_flush_buffer(%d) called\n", tty->index); - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info.xmit); if (port->ops->flush_buffer) port->ops->flush_buffer(port); - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); tty_wakeup(tty); } @@ -598,9 +598,9 @@ else { port->x_char = ch; if (ch) { - spin_lock_irqsave(&port->lock, flags); + atomic_spin_lock_irqsave(&port->lock, flags); port->ops->start_tx(port); - spin_unlock_irqrestore(&port->lock, flags); + atomic_spin_unlock_irqrestore(&port->lock, flags); } } } @@ -910,9 +910,9 @@ !(tty->flags & (1 << TTY_IO_ERROR))) { result = port->mctrl; - spin_lock_irq(&port->lock); + atomic_spin_lock_irq(&port->lock); result |= port->ops->get_mctrl(port); - spin_unlock_irq(&port->lock); + atomic_spin_unlock_irq(&port->lock); } mutex_unlock(&state->mutex); @@ -1011,20 +1011,20 @@ /* * note the counters on entry */ - spin_lock_irq(&port->lock); + atomic_spin_lock_irq(&port->lock); memcpy(&cprev, &port->icount, sizeof(struct uart_icount)); /* * Force modem status interrupts on */ port->ops->enable_ms(port); - spin_unlock_irq(&port->lock); + atomic_spin_unlock_irq(&port->lock); add_wait_queue(&state->info.delta_msr_wait, &wait); for (;;) { - spin_lock_irq(&port->lock); + atomic_spin_lock_irq(&port->lock); memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&port->lock); + atomic_spin_unlock_irq(&port->lock); set_current_state(TASK_INTERRUPTIBLE); @@ -1066,9 +1066,9 @@ struct uart_icount cnow; struct uart_port *port = state->port; - spin_lock_irq(&port->lock); + atomic_spin_lock_irq(&port->lock); memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&port->lock); + atomic_spin_unlock_irq(&port->lock); icount.cts = cnow.cts; icount.dsr = cnow.dsr; @@ -1220,20 +1220,20 @@ /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - spin_lock_irqsave(&state->port->lock, flags); + atomic_spin_lock_irqsave(&state->port->lock, flags); tty->hw_stopped = 0; __uart_start(tty); - spin_unlock_irqrestore(&state->port->lock, flags); + atomic_spin_unlock_irqrestore(&state->port->lock, flags); } /* Handle turning on CRTSCTS */ if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { - spin_lock_irqsave(&state->port->lock, flags); + atomic_spin_lock_irqsave(&state->po...stripped-down
I also configured kernel to support high-resolution timers with 1 ms period. If somebody interested in this stuff I'll post here patches.
Hi Maksim, Forum posts are limited to 10k characters. That is why your previous post is stripped down. But I have now added an attachment function for registered/logged-in users. Regards, Andreas
Hi, Maksim, could you post the high resolution timer patches for 2.6.31, as well as the ones that solve the ttySAC0 IRQ problem? Also, I noticed that S3C2440 has three resolution timers that can go as low as a few microseconds. Is there a way to lower the resolution in your patches? Thanks, R.