aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/sirfsoc_uart.c
diff options
context:
space:
mode:
authorQipan Li <Qipan.Li@csr.com>2014-05-26 07:02:07 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-28 15:22:43 -0400
commit07d410e06463f3c1c106e2bb2a7ff23eff1e71c9 (patch)
treeb8b6092ae11b4856fac7720215be563ee089598c /drivers/tty/serial/sirfsoc_uart.c
parent205c384f73e56d6b7d309b883a2064cd07ab5427 (diff)
serial: sirf: fix spinlock deadlock issue
commit fb78b811422cd2d8c8605949cc4cc13618347ad5 provide a workaround for kernel panic, but bring potential deadlock risk. that is in sirfsoc_rx_tmo_process_tl while enter into sirfsoc_uart_pio_rx_chars cpu hold uart_port->lock, if uart interrupt comes cpu enter into sirfsoc_uart_isr and deadlock occurs in getting uart_port->lock. the patch replace spin_lock version to spin_lock_irq* version to avoid spinlock dead lock issue. let function tty_flip_buffer_push in tasklet outof spin_lock_irq* protect area to avoid add the pair of spin_lock and spin_unlock for tty_flip_buffer_push. BTW drop self defined unused spinlock protect of tx_lock/rx_lock. 56274.220464] BUG: spinlock lockup suspected on CPU#0, swapper/0/0 [56274.223648] lock: 0xc05d9db0, .magic: dead4ead, .owner: swapper/0/0, .owner_cpu: 0 [56274.231278] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 3.10.35 #1 [56274.238241] [<c0015530>] (unwind_backtrace+0x0/0xf4) from [<c00120d8>] (show_stack+0x10/0x14) [56274.246742] [<c00120d8>] (show_stack+0x10/0x14) from [<c01b11b0>] (do_raw_spin_lock+0x110/0x184) [56274.255501] [<c01b11b0>] (do_raw_spin_lock+0x110/0x184) from [<c02124c8>] (sirfsoc_uart_isr+0x20/0x42c) [56274.264874] [<c02124c8>] (sirfsoc_uart_isr+0x20/0x42c) from [<c0075790>] (handle_irq_event_percpu+0x54/0x17c) [56274.274758] [<c0075790>] (handle_irq_event_percpu+0x54/0x17c) from [<c00758f4>] (handle_irq_event+0x3c/0x5c) [56274.284561] [<c00758f4>] (handle_irq_event+0x3c/0x5c) from [<c0077fa0>] (handle_level_irq+0x98/0xfc) [56274.293670] [<c0077fa0>] (handle_level_irq+0x98/0xfc) from [<c0074f44>] (generic_handle_irq+0x2c/0x3c) [56274.302952] [<c0074f44>] (generic_handle_irq+0x2c/0x3c) from [<c000ef80>] (handle_IRQ+0x40/0x90) [56274.311706] [<c000ef80>] (handle_IRQ+0x40/0x90) from [<c000dc80>] (__irq_svc+0x40/0x70) [56274.319697] [<c000dc80>] (__irq_svc+0x40/0x70) from [<c038113c>] (_raw_spin_unlock_irqrestore+0x10/0x48) [56274.329158] [<c038113c>] (_raw_spin_unlock_irqrestore+0x10/0x48) from [<c0200034>] (tty_port_tty_get+0x58/0x90) [56274.339213] [<c0200034>] (tty_port_tty_get+0x58/0x90) from [<c0212008>] (sirfsoc_uart_pio_rx_chars+0x1c/0xc8) [56274.349097] [<c0212008>] (sirfsoc_uart_pio_rx_chars+0x1c/0xc8) from [<c0212ef8>] (sirfsoc_rx_tmo_process_tl+0xe4/0x1fc) [56274.359853] [<c0212ef8>] (sirfsoc_rx_tmo_process_tl+0xe4/0x1fc) from [<c0027c04>] (tasklet_action+0x84/0x114) [56274.369739] [<c0027c04>] (tasklet_action+0x84/0x114) from [<c0027db4>] (__do_softirq+0x120/0x200) [56274.378585] [<c0027db4>] (__do_softirq+0x120/0x200) from [<c0027f44>] (do_softirq+0x54/0x5c) [56274.386998] [<c0027f44>] (do_softirq+0x54/0x5c) from [<c00281ec>] (irq_exit+0x9c/0xd0) [56274.394899] [<c00281ec>] (irq_exit+0x9c/0xd0) from [<c000ef84>] (handle_IRQ+0x44/0x90) [56274.402790] [<c000ef84>] (handle_IRQ+0x44/0x90) from [<c000dc80>] (__irq_svc+0x40/0x70) [56274.410774] [<c000dc80>] (__irq_svc+0x40/0x70) from [<c0288af4>] (cpuidle_enter_state+0x50/0xe0) [56274.419532] [<c0288af4>] (cpuidle_enter_state+0x50/0xe0) from [<c0288c34>] (cpuidle_idle_call+0xb0/0x148) [56274.429080] [<c0288c34>] (cpuidle_idle_call+0xb0/0x148) from [<c000f3ac>] (arch_cpu_idle+0x8/0x38) [56274.438016] [<c000f3ac>] (arch_cpu_idle+0x8/0x38) from [<c0059344>] (cpu_startup_entry+0xfc/0x140) [56274.446956] [<c0059344>] (cpu_startup_entry+0xfc/0x140) from [<c04a3a54>] (start_kernel+0x2d8/0x2e4) Signed-off-by: Qipan Li <Qipan.Li@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/sirfsoc_uart.c')
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c49
1 files changed, 18 insertions, 31 deletions
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 845548cf05f8..236f892dab9c 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -358,9 +358,11 @@ static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
358{ 358{
359 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id; 359 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
360 struct uart_port *port = &sirfport->port; 360 struct uart_port *port = &sirfport->port;
361 spin_lock(&port->lock);
361 if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled) 362 if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
362 uart_handle_cts_change(port, 363 uart_handle_cts_change(port,
363 !gpio_get_value(sirfport->cts_gpio)); 364 !gpio_get_value(sirfport->cts_gpio));
365 spin_unlock(&port->lock);
364 return IRQ_HANDLED; 366 return IRQ_HANDLED;
365} 367}
366 368
@@ -428,10 +430,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
428 sirfport->rx_io_count += rx_count; 430 sirfport->rx_io_count += rx_count;
429 port->icount.rx += rx_count; 431 port->icount.rx += rx_count;
430 432
431 spin_unlock(&port->lock);
432 tty_flip_buffer_push(&port->state->port);
433 spin_lock(&port->lock);
434
435 return rx_count; 433 return rx_count;
436} 434}
437 435
@@ -465,6 +463,7 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
465 struct circ_buf *xmit = &port->state->xmit; 463 struct circ_buf *xmit = &port->state->xmit;
466 unsigned long flags; 464 unsigned long flags;
467 465
466 spin_lock_irqsave(&port->lock, flags);
468 xmit->tail = (xmit->tail + sirfport->transfer_size) & 467 xmit->tail = (xmit->tail + sirfport->transfer_size) &
469 (UART_XMIT_SIZE - 1); 468 (UART_XMIT_SIZE - 1);
470 port->icount.tx += sirfport->transfer_size; 469 port->icount.tx += sirfport->transfer_size;
@@ -473,10 +472,9 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
473 if (sirfport->tx_dma_addr) 472 if (sirfport->tx_dma_addr)
474 dma_unmap_single(port->dev, sirfport->tx_dma_addr, 473 dma_unmap_single(port->dev, sirfport->tx_dma_addr,
475 sirfport->transfer_size, DMA_TO_DEVICE); 474 sirfport->transfer_size, DMA_TO_DEVICE);
476 spin_lock_irqsave(&sirfport->tx_lock, flags);
477 sirfport->tx_dma_state = TX_DMA_IDLE; 475 sirfport->tx_dma_state = TX_DMA_IDLE;
478 sirfsoc_uart_tx_with_dma(sirfport); 476 sirfsoc_uart_tx_with_dma(sirfport);
479 spin_unlock_irqrestore(&sirfport->tx_lock, flags); 477 spin_unlock_irqrestore(&port->lock, flags);
480} 478}
481 479
482static void sirfsoc_uart_insert_rx_buf_to_tty( 480static void sirfsoc_uart_insert_rx_buf_to_tty(
@@ -489,7 +487,6 @@ static void sirfsoc_uart_insert_rx_buf_to_tty(
489 inserted = tty_insert_flip_string(tport, 487 inserted = tty_insert_flip_string(tport,
490 sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count); 488 sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
491 port->icount.rx += inserted; 489 port->icount.rx += inserted;
492 tty_flip_buffer_push(tport);
493} 490}
494 491
495static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index) 492static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
@@ -525,7 +522,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
525 unsigned long flags; 522 unsigned long flags;
526 struct dma_tx_state tx_state; 523 struct dma_tx_state tx_state;
527 524
528 spin_lock_irqsave(&sirfport->rx_lock, flags); 525 spin_lock_irqsave(&port->lock, flags);
529 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, 526 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
530 sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { 527 sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
531 sirfsoc_uart_insert_rx_buf_to_tty(sirfport, 528 sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@@ -541,12 +538,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
541 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, 538 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
542 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | 539 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
543 SIRFUART_IO_MODE); 540 SIRFUART_IO_MODE);
544 spin_unlock_irqrestore(&sirfport->rx_lock, flags);
545 spin_lock(&port->lock);
546 sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); 541 sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
547 spin_unlock(&port->lock);
548 if (sirfport->rx_io_count == 4) { 542 if (sirfport->rx_io_count == 4) {
549 spin_lock_irqsave(&sirfport->rx_lock, flags);
550 sirfport->rx_io_count = 0; 543 sirfport->rx_io_count = 0;
551 wr_regl(port, ureg->sirfsoc_int_st_reg, 544 wr_regl(port, ureg->sirfsoc_int_st_reg,
552 uint_st->sirfsoc_rx_done); 545 uint_st->sirfsoc_rx_done);
@@ -557,11 +550,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
557 else 550 else
558 wr_regl(port, SIRFUART_INT_EN_CLR, 551 wr_regl(port, SIRFUART_INT_EN_CLR,
559 uint_en->sirfsoc_rx_done_en); 552 uint_en->sirfsoc_rx_done_en);
560 spin_unlock_irqrestore(&sirfport->rx_lock, flags);
561
562 sirfsoc_uart_start_next_rx_dma(port); 553 sirfsoc_uart_start_next_rx_dma(port);
563 } else { 554 } else {
564 spin_lock_irqsave(&sirfport->rx_lock, flags);
565 wr_regl(port, ureg->sirfsoc_int_st_reg, 555 wr_regl(port, ureg->sirfsoc_int_st_reg,
566 uint_st->sirfsoc_rx_done); 556 uint_st->sirfsoc_rx_done);
567 if (!sirfport->is_marco) 557 if (!sirfport->is_marco)
@@ -571,8 +561,9 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
571 else 561 else
572 wr_regl(port, ureg->sirfsoc_int_en_reg, 562 wr_regl(port, ureg->sirfsoc_int_en_reg,
573 uint_en->sirfsoc_rx_done_en); 563 uint_en->sirfsoc_rx_done_en);
574 spin_unlock_irqrestore(&sirfport->rx_lock, flags);
575 } 564 }
565 spin_unlock_irqrestore(&port->lock, flags);
566 tty_flip_buffer_push(&port->state->port);
576} 567}
577 568
578static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport) 569static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
@@ -581,8 +572,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
581 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; 572 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
582 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; 573 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
583 struct dma_tx_state tx_state; 574 struct dma_tx_state tx_state;
584 spin_lock(&sirfport->rx_lock);
585
586 dmaengine_tx_status(sirfport->rx_dma_chan, 575 dmaengine_tx_status(sirfport->rx_dma_chan,
587 sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state); 576 sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
588 dmaengine_terminate_all(sirfport->rx_dma_chan); 577 dmaengine_terminate_all(sirfport->rx_dma_chan);
@@ -595,7 +584,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
595 else 584 else
596 wr_regl(port, SIRFUART_INT_EN_CLR, 585 wr_regl(port, SIRFUART_INT_EN_CLR,
597 uint_en->sirfsoc_rx_timeout_en); 586 uint_en->sirfsoc_rx_timeout_en);
598 spin_unlock(&sirfport->rx_lock);
599 tasklet_schedule(&sirfport->rx_tmo_process_tasklet); 587 tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
600} 588}
601 589
@@ -659,7 +647,6 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
659 intr_status &= port->read_status_mask; 647 intr_status &= port->read_status_mask;
660 uart_insert_char(port, intr_status, 648 uart_insert_char(port, intr_status,
661 uint_en->sirfsoc_rx_oflow_en, 0, flag); 649 uint_en->sirfsoc_rx_oflow_en, 0, flag);
662 tty_flip_buffer_push(&state->port);
663 } 650 }
664recv_char: 651recv_char:
665 if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) && 652 if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
@@ -684,6 +671,9 @@ recv_char:
684 sirfsoc_uart_pio_rx_chars(port, 671 sirfsoc_uart_pio_rx_chars(port,
685 SIRFSOC_UART_IO_RX_MAX_CNT); 672 SIRFSOC_UART_IO_RX_MAX_CNT);
686 } 673 }
674 spin_unlock(&port->lock);
675 tty_flip_buffer_push(&state->port);
676 spin_lock(&port->lock);
687 if (intr_status & uint_st->sirfsoc_txfifo_empty) { 677 if (intr_status & uint_st->sirfsoc_txfifo_empty) {
688 if (sirfport->tx_dma_chan) 678 if (sirfport->tx_dma_chan)
689 sirfsoc_uart_tx_with_dma(sirfport); 679 sirfsoc_uart_tx_with_dma(sirfport);
@@ -702,6 +692,7 @@ recv_char:
702 } 692 }
703 } 693 }
704 spin_unlock(&port->lock); 694 spin_unlock(&port->lock);
695
705 return IRQ_HANDLED; 696 return IRQ_HANDLED;
706} 697}
707 698
@@ -713,7 +704,7 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
713 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; 704 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
714 unsigned long flags; 705 unsigned long flags;
715 struct dma_tx_state tx_state; 706 struct dma_tx_state tx_state;
716 spin_lock_irqsave(&sirfport->rx_lock, flags); 707 spin_lock_irqsave(&port->rx_lock, flags);
717 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, 708 while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
718 sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { 709 sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
719 sirfsoc_uart_insert_rx_buf_to_tty(sirfport, 710 sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@@ -726,17 +717,20 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
726 sirfport->rx_completed++; 717 sirfport->rx_completed++;
727 sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; 718 sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
728 } 719 }
729 spin_unlock_irqrestore(&sirfport->rx_lock, flags); 720 spin_unlock_irqrestore(&port->lock, flags);
721 tty_flip_buffer_push(&port->state->port);
730} 722}
731 723
732static void sirfsoc_uart_rx_dma_complete_callback(void *param) 724static void sirfsoc_uart_rx_dma_complete_callback(void *param)
733{ 725{
734 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; 726 struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
735 spin_lock(&sirfport->rx_lock); 727 unsigned long flags;
728
729 spin_lock_irqsave(&sirfport->port.lock, flags);
736 sirfport->rx_issued++; 730 sirfport->rx_issued++;
737 sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT; 731 sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
738 spin_unlock(&sirfport->rx_lock);
739 tasklet_schedule(&sirfport->rx_dma_complete_tasklet); 732 tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
733 spin_unlock_irqrestore(&sirfport->port.lock, flags);
740} 734}
741 735
742/* submit rx dma task into dmaengine */ 736/* submit rx dma task into dmaengine */
@@ -745,18 +739,14 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
745 struct sirfsoc_uart_port *sirfport = to_sirfport(port); 739 struct sirfsoc_uart_port *sirfport = to_sirfport(port);
746 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; 740 struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
747 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; 741 struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
748 unsigned long flags;
749 int i; 742 int i;
750 spin_lock_irqsave(&sirfport->rx_lock, flags);
751 sirfport->rx_io_count = 0; 743 sirfport->rx_io_count = 0;
752 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, 744 wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
753 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & 745 rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
754 ~SIRFUART_IO_MODE); 746 ~SIRFUART_IO_MODE);
755 spin_unlock_irqrestore(&sirfport->rx_lock, flags);
756 for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) 747 for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
757 sirfsoc_rx_submit_one_dma_desc(port, i); 748 sirfsoc_rx_submit_one_dma_desc(port, i);
758 sirfport->rx_completed = sirfport->rx_issued = 0; 749 sirfport->rx_completed = sirfport->rx_issued = 0;
759 spin_lock_irqsave(&sirfport->rx_lock, flags);
760 if (!sirfport->is_marco) 750 if (!sirfport->is_marco)
761 wr_regl(port, ureg->sirfsoc_int_en_reg, 751 wr_regl(port, ureg->sirfsoc_int_en_reg,
762 rd_regl(port, ureg->sirfsoc_int_en_reg) | 752 rd_regl(port, ureg->sirfsoc_int_en_reg) |
@@ -764,7 +754,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
764 else 754 else
765 wr_regl(port, ureg->sirfsoc_int_en_reg, 755 wr_regl(port, ureg->sirfsoc_int_en_reg,
766 SIRFUART_RX_DMA_INT_EN(port, uint_en)); 756 SIRFUART_RX_DMA_INT_EN(port, uint_en));
767 spin_unlock_irqrestore(&sirfport->rx_lock, flags);
768} 757}
769 758
770static void sirfsoc_uart_start_rx(struct uart_port *port) 759static void sirfsoc_uart_start_rx(struct uart_port *port)
@@ -1369,8 +1358,6 @@ usp_no_flow_control:
1369 ret = -EFAULT; 1358 ret = -EFAULT;
1370 goto err; 1359 goto err;
1371 } 1360 }
1372 spin_lock_init(&sirfport->rx_lock);
1373 spin_lock_init(&sirfport->tx_lock);
1374 tasklet_init(&sirfport->rx_dma_complete_tasklet, 1361 tasklet_init(&sirfport->rx_dma_complete_tasklet,
1375 sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport); 1362 sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
1376 tasklet_init(&sirfport->rx_tmo_process_tasklet, 1363 tasklet_init(&sirfport->rx_tmo_process_tasklet,