Hi all,
I applied 'patch-2.6.31.4-rt14' patch from http://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
Re: 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:
Code: Select all
--- 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->port->lock, flags);
if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
tty->hw_stopped = 1;
state->port->ops->stop_tx(state->port);
}
- spin_unlock_irqrestore(&state->port->lock, flags);
+ atomic_spin_unlock_irqrestore(&state->port->lock, flags);
}
#if 0
/*
@@ -1308,9 +1308,9 @@
*/
if (state->info.flags & UIF_INITIALIZED) {
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
+ atomic_spin_lock_irqsave(&port->lock, flags);
port->ops->stop_rx(port);
- spin_unlock_irqrestore(&port->lock, flags);
+ atomic_spin_unlock_irqrestore(&port->lock, flags);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
@@ -1522,10 +1522,10 @@
* and wait for the carrier to indicate that the
* modem is ready for us.
*/
- spin_lock_irq(&port->lock);
+ atomic_spin_lock_irq(&port->lock);
port->ops->enable_ms(port);
mctrl = port->ops->get_mctrl(port);
- spin_unlock_irq(&port->lock);
+ atomic_spin_unlock_irq(&port->lock);
if (mctrl & TIOCM_CAR)
break;
@@ -1714,9 +1714,9 @@
pm_state = state->pm_state;
if (pm_state)
uart_change_pm(state, 0);
- spin_lock_irq(&port->lock);
+ atomic_spin_lock_irq(&port->lock);
status = port->ops->get_mctrl(port);
- spin_unlock_irq(&port->lock);
+ atomic_spin_unlock_irq(&port->lock);
if (pm_state)
uart_change_pm(state, pm_state);
mutex_unlock(&state->mutex);
@@ -2012,11 +2012,11 @@
state->info.flags = (state->info.flags & ~UIF_INITIALIZED)
| UIF_SUSPENDED;
- spin_lock_irq(&port->lock);
+ atomic_spin_lock_irq(&port->lock);
ops->stop_tx(port);
ops->set_mctrl(port, 0);
ops->stop_rx(port);
- spin_unlock_irq(&port->lock);
+ atomic_spin_unlock_irq(&port->lock);
/*
* Wait for the transmitter to empty.
@@ -2097,16 +2097,16 @@
int ret;
uart_change_pm(state, 0);
- spin_lock_irq(&port->lock);
+ atomic_spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0);
- spin_unlock_irq(&port->lock);
+ atomic_spin_unlock_irq(&port->lock);
ret = ops->startup(port);
if (ret == 0) {
uart_change_speed(state, NULL);
- spin_lock_irq(&port->lock);
+ atomic_spin_lock_irq(&port->lock);
ops->set_mctrl(port, port->mctrl);
ops->start_tx(port);
- spin_unlock_irq(&port->lock);
+ atomic_spin_unlock_irq(&port->lock);
state->info.flags |= UIF_INITIALIZED;
} else {
/*
@@ -2199,9 +2199,9 @@
* keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
*/
- spin_lock_irqsave(&port->lock, flags);
+ atomic_spin_lock_irqsave(&port->lock, flags);
port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
- spin_unlock_irqrestore(&port->lock, flags);
+ atomic_spin_unlock_irqrestore(&port->lock, flags);
/*
* If this driver supports console, and it hasn't been
- Attachments
-
- patch-2.6.31-rt_serial_irq.patch.tar.gz
- Patch for 2.6.31 kernel with real-time patch - workaround for issue with busy loop on serial IRQ (71)
- (2.43 KiB) Downloaded 455 times
Re: ttySAC0 issue on 2.6.31 after real time patch
I also configured kernel to support high-resolution timers with 1 ms period. If somebody interested in this stuff I'll post here patches.
Who is online
Users browsing this forum: No registered users and 5 guests