summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/mvf.c
diff options
context:
space:
mode:
authorAndy Voltz <andy.voltz@timesys.com>2013-03-14 15:09:50 -0400
committerAndy Voltz <andy.voltz@timesys.com>2013-03-14 15:09:50 -0400
commitc0cfb5767277856a41ae2dd1ed31dfd8cb37f2a0 (patch)
tree4374d1a98b761d0b2f8e89ea98b20413d8a7ce91 /drivers/tty/serial/mvf.c
parent4cbca527d4ab6175ec14887b99e88a70c6b34621 (diff)
Fix serial bug when recieving a file3.0-vybrid-ts2
When serial-transmit a file from host to target, an error "BUG: scheduling while atomic: cat/998/0x00010002" occurs. BUG: scheduling while atomic: cat/998/0x00010002 Modules linked in: Pid: 998, comm: cat CPU: 0 Not tainted (3.0.15 #1) PC is at n_tty_write+0x260/0x43c LR is at tty_write_room+0x20/0x2c pc : <80204700> lr : <80206194> psr: 60000013 sp : 863b9e78 ip : 8038e378 fp : 863b9ec4 r10: 00000fff r9 : 863b6400 r8 : 86165d80 r7 : 863b8000 r6 : 86368b6c r5 : 86368800 r4 : 00000002 r3 : 00000010 r2 : 00000000 r1 : 00000040 r0 : 00000002 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: 863f8059 DAC: 00000015 <80031f5c> (show_regs+0x0/0x54) from <803761f0> (__schedule_bug+0x4c/0x60) r4:863b9e30 r3:60000193 <803761a4> (__schedule_bug+0x0/0x60) from <8037941c> (__schedule+0x35c/0x3c4) Thanks to Tadayoshi Arai <ara@lineo.co.jp> for reporting this and submitting this patch
Diffstat (limited to 'drivers/tty/serial/mvf.c')
-rw-r--r--drivers/tty/serial/mvf.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/tty/serial/mvf.c b/drivers/tty/serial/mvf.c
index a65a275c7c98..66dba76081e8 100644
--- a/drivers/tty/serial/mvf.c
+++ b/drivers/tty/serial/mvf.c
@@ -98,7 +98,7 @@ struct imx_port {
void *rx_buf;
unsigned char *tx_buf;
unsigned int rx_bytes, tx_bytes;
- struct work_struct tsk_dma_rx, tsk_dma_tx;
+ struct work_struct tsk_rx, tsk_dma_tx;
unsigned int dma_tx_nents;
bool dma_is_rxing, dma_is_txing;
wait_queue_head_t dma_wait;
@@ -384,6 +384,17 @@ out:
return IRQ_HANDLED;
}
+static void rx_work(struct work_struct *w)
+{
+ struct imx_port *sport = container_of(w, struct imx_port, tsk_rx);
+ struct tty_struct *tty = sport->port.state->port.tty;
+
+ if (sport->rx_bytes) {
+ tty_flip_buffer_push(tty);
+ sport->rx_bytes = 0;
+ }
+}
+
static irqreturn_t imx_rxint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
@@ -445,12 +456,13 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
uart_insert_char(sport->port, sr, MXC_UARTSR1_OR, rx, flg);
*/
tty_insert_flip_char(tty, rx, flg);
+ sport->rx_bytes++;
}
out:
spin_unlock_irqrestore(&sport->port.lock, flags);
- tty_flip_buffer_push(tty);
+ schedule_work(&sport->tsk_rx);
return IRQ_HANDLED;
}
@@ -640,7 +652,7 @@ static int imx_startup(struct uart_port *port)
sport->port.flags |= UPF_LOW_LATENCY;
INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
- /*INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);*/
+ INIT_WORK(&sport->tsk_rx, rx_work);
init_waitqueue_head(&sport->dma_wait);
}