ttySAC0 issue on 2.6.31 after real time patch

Post Reply
mgalemin
Posts: 13
Joined: Tue Oct 06, 2009 11:49 pm

ttySAC0 issue on 2.6.31 after real time patch

Post by mgalemin » Wed Oct 21, 2009 8:29 am

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!

mgalemin
Posts: 13
Joined: Tue Oct 06, 2009 11:49 pm

Re: ttySAC0 issue on 2.6.31 after real time patch

Post by mgalemin » Mon Nov 09, 2009 2:16 am

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 241 times

mgalemin
Posts: 13
Joined: Tue Oct 06, 2009 11:49 pm

Re: ttySAC0 issue on 2.6.31 after real time patch

Post by mgalemin » Mon Nov 09, 2009 10:06 am

I also configured kernel to support high-resolution timers with 1 ms period. If somebody interested in this stuff I'll post here patches.

Post Reply

Who is online

Users browsing this forum: No registered users and 14 guests