diff options
Diffstat (limited to 'arch/mn10300/kernel/mn10300-serial.c')
-rw-r--r-- | arch/mn10300/kernel/mn10300-serial.c | 121 |
1 files changed, 78 insertions, 43 deletions
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c index cac0f0da9203..587545cb7e4c 100644 --- a/arch/mn10300/kernel/mn10300-serial.c +++ b/arch/mn10300/kernel/mn10300-serial.c | |||
@@ -444,25 +444,53 @@ struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS]; | |||
444 | 444 | ||
445 | static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port) | 445 | static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port) |
446 | { | 446 | { |
447 | unsigned long flags; | 447 | int retries = 100; |
448 | u16 x; | 448 | u16 x; |
449 | 449 | ||
450 | flags = arch_local_cli_save(); | 450 | /* nothing to do if irq isn't set up */ |
451 | *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | 451 | if (!mn10300_serial_int_tbl[port->tx_irq].port) |
452 | x = *port->tx_icr; | 452 | return; |
453 | arch_local_irq_restore(flags); | 453 | |
454 | port->tx_flags |= MNSCx_TX_STOP; | ||
455 | mb(); | ||
456 | |||
457 | /* | ||
458 | * Here we wait for the irq to be disabled. Either it already is | ||
459 | * disabled or we wait some number of retries for the VDMA handler | ||
460 | * to disable it. The retries give the VDMA handler enough time to | ||
461 | * run to completion if it was already in progress. If the VDMA IRQ | ||
462 | * is enabled but the handler is not yet running when arrive here, | ||
463 | * the STOP flag will prevent the handler from conflicting with the | ||
464 | * driver code following this loop. | ||
465 | */ | ||
466 | while ((*port->tx_icr & GxICR_ENABLE) && retries-- > 0) | ||
467 | ; | ||
468 | if (retries <= 0) { | ||
469 | *port->tx_icr = | ||
470 | NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | ||
471 | x = *port->tx_icr; | ||
472 | } | ||
454 | } | 473 | } |
455 | 474 | ||
456 | static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port) | 475 | static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port) |
457 | { | 476 | { |
458 | unsigned long flags; | ||
459 | u16 x; | 477 | u16 x; |
460 | 478 | ||
461 | flags = arch_local_cli_save(); | 479 | /* nothing to do if irq isn't set up */ |
480 | if (!mn10300_serial_int_tbl[port->tx_irq].port) | ||
481 | return; | ||
482 | |||
483 | /* stop vdma irq if not already stopped */ | ||
484 | if (!(port->tx_flags & MNSCx_TX_STOP)) | ||
485 | mn10300_serial_dis_tx_intr(port); | ||
486 | |||
487 | port->tx_flags &= ~MNSCx_TX_STOP; | ||
488 | mb(); | ||
489 | |||
462 | *port->tx_icr = | 490 | *port->tx_icr = |
463 | NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE; | 491 | NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | |
492 | GxICR_ENABLE | GxICR_REQUEST | GxICR_DETECT; | ||
464 | x = *port->tx_icr; | 493 | x = *port->tx_icr; |
465 | arch_local_irq_restore(flags); | ||
466 | } | 494 | } |
467 | 495 | ||
468 | static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port) | 496 | static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port) |
@@ -807,8 +835,6 @@ static void mn10300_serial_start_tx(struct uart_port *_port) | |||
807 | struct mn10300_serial_port *port = | 835 | struct mn10300_serial_port *port = |
808 | container_of(_port, struct mn10300_serial_port, uart); | 836 | container_of(_port, struct mn10300_serial_port, uart); |
809 | 837 | ||
810 | u16 x; | ||
811 | |||
812 | _enter("%s{%lu}", | 838 | _enter("%s{%lu}", |
813 | port->name, | 839 | port->name, |
814 | CIRC_CNT(&port->uart.state->xmit.head, | 840 | CIRC_CNT(&port->uart.state->xmit.head, |
@@ -816,14 +842,7 @@ static void mn10300_serial_start_tx(struct uart_port *_port) | |||
816 | UART_XMIT_SIZE)); | 842 | UART_XMIT_SIZE)); |
817 | 843 | ||
818 | /* kick the virtual DMA controller */ | 844 | /* kick the virtual DMA controller */ |
819 | arch_local_cli(); | 845 | mn10300_serial_en_tx_intr(port); |
820 | x = *port->tx_icr; | ||
821 | x |= GxICR_ENABLE; | ||
822 | |||
823 | if (*port->_status & SC01STR_TBF) | ||
824 | x &= ~(GxICR_REQUEST | GxICR_DETECT); | ||
825 | else | ||
826 | x |= GxICR_REQUEST | GxICR_DETECT; | ||
827 | 846 | ||
828 | _debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx", | 847 | _debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx", |
829 | *port->_control, *port->_intr, *port->_status, | 848 | *port->_control, *port->_intr, *port->_status, |
@@ -831,10 +850,6 @@ static void mn10300_serial_start_tx(struct uart_port *_port) | |||
831 | (port->div_timer == MNSCx_DIV_TIMER_8BIT) ? | 850 | (port->div_timer == MNSCx_DIV_TIMER_8BIT) ? |
832 | *(volatile u8 *)port->_tmxbr : *port->_tmxbr, | 851 | *(volatile u8 *)port->_tmxbr : *port->_tmxbr, |
833 | *port->tx_icr); | 852 | *port->tx_icr); |
834 | |||
835 | *port->tx_icr = x; | ||
836 | x = *port->tx_icr; | ||
837 | arch_local_sti(); | ||
838 | } | 853 | } |
839 | 854 | ||
840 | /* | 855 | /* |
@@ -844,13 +859,17 @@ static void mn10300_serial_send_xchar(struct uart_port *_port, char ch) | |||
844 | { | 859 | { |
845 | struct mn10300_serial_port *port = | 860 | struct mn10300_serial_port *port = |
846 | container_of(_port, struct mn10300_serial_port, uart); | 861 | container_of(_port, struct mn10300_serial_port, uart); |
862 | unsigned long flags; | ||
847 | 863 | ||
848 | _enter("%s,%02x", port->name, ch); | 864 | _enter("%s,%02x", port->name, ch); |
849 | 865 | ||
850 | if (likely(port->gdbstub)) { | 866 | if (likely(port->gdbstub)) { |
851 | port->tx_xchar = ch; | 867 | port->tx_xchar = ch; |
852 | if (ch) | 868 | if (ch) { |
869 | spin_lock_irqsave(&port->uart.lock, flags); | ||
853 | mn10300_serial_en_tx_intr(port); | 870 | mn10300_serial_en_tx_intr(port); |
871 | spin_unlock_irqrestore(&port->uart.lock, flags); | ||
872 | } | ||
854 | } | 873 | } |
855 | } | 874 | } |
856 | 875 | ||
@@ -911,18 +930,21 @@ static void mn10300_serial_break_ctl(struct uart_port *_port, int ctl) | |||
911 | { | 930 | { |
912 | struct mn10300_serial_port *port = | 931 | struct mn10300_serial_port *port = |
913 | container_of(_port, struct mn10300_serial_port, uart); | 932 | container_of(_port, struct mn10300_serial_port, uart); |
933 | unsigned long flags; | ||
914 | 934 | ||
915 | _enter("%s,%d", port->name, ctl); | 935 | _enter("%s,%d", port->name, ctl); |
916 | 936 | ||
937 | spin_lock_irqsave(&port->uart.lock, flags); | ||
917 | if (ctl) { | 938 | if (ctl) { |
918 | /* tell the virtual DMA handler to assert BREAK */ | 939 | /* tell the virtual DMA handler to assert BREAK */ |
919 | port->tx_break = 1; | 940 | port->tx_flags |= MNSCx_TX_BREAK; |
920 | mn10300_serial_en_tx_intr(port); | 941 | mn10300_serial_en_tx_intr(port); |
921 | } else { | 942 | } else { |
922 | port->tx_break = 0; | 943 | port->tx_flags &= ~MNSCx_TX_BREAK; |
923 | *port->_control &= ~SC01CTR_BKE; | 944 | *port->_control &= ~SC01CTR_BKE; |
924 | mn10300_serial_en_tx_intr(port); | 945 | mn10300_serial_en_tx_intr(port); |
925 | } | 946 | } |
947 | spin_unlock_irqrestore(&port->uart.lock, flags); | ||
926 | } | 948 | } |
927 | 949 | ||
928 | /* | 950 | /* |
@@ -945,6 +967,7 @@ static int mn10300_serial_startup(struct uart_port *_port) | |||
945 | return -ENOMEM; | 967 | return -ENOMEM; |
946 | 968 | ||
947 | port->rx_inp = port->rx_outp = 0; | 969 | port->rx_inp = port->rx_outp = 0; |
970 | port->tx_flags = 0; | ||
948 | 971 | ||
949 | /* finally, enable the device */ | 972 | /* finally, enable the device */ |
950 | *port->_intr = SC01ICR_TI; | 973 | *port->_intr = SC01ICR_TI; |
@@ -994,14 +1017,22 @@ error: | |||
994 | */ | 1017 | */ |
995 | static void mn10300_serial_shutdown(struct uart_port *_port) | 1018 | static void mn10300_serial_shutdown(struct uart_port *_port) |
996 | { | 1019 | { |
1020 | unsigned long flags; | ||
997 | u16 x; | 1021 | u16 x; |
998 | struct mn10300_serial_port *port = | 1022 | struct mn10300_serial_port *port = |
999 | container_of(_port, struct mn10300_serial_port, uart); | 1023 | container_of(_port, struct mn10300_serial_port, uart); |
1000 | 1024 | ||
1001 | _enter("%s", port->name); | 1025 | _enter("%s", port->name); |
1002 | 1026 | ||
1027 | spin_lock_irqsave(&_port->lock, flags); | ||
1028 | mn10300_serial_dis_tx_intr(port); | ||
1029 | |||
1030 | *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | ||
1031 | x = *port->rx_icr; | ||
1032 | port->tx_flags = 0; | ||
1033 | spin_unlock_irqrestore(&_port->lock, flags); | ||
1034 | |||
1003 | /* disable the serial port and its baud rate timer */ | 1035 | /* disable the serial port and its baud rate timer */ |
1004 | port->tx_break = 0; | ||
1005 | *port->_control &= ~(SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE); | 1036 | *port->_control &= ~(SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE); |
1006 | *port->_tmxmd = 0; | 1037 | *port->_tmxmd = 0; |
1007 | 1038 | ||
@@ -1016,12 +1047,8 @@ static void mn10300_serial_shutdown(struct uart_port *_port) | |||
1016 | free_irq(port->rx_irq, port); | 1047 | free_irq(port->rx_irq, port); |
1017 | free_irq(port->tx_irq, port); | 1048 | free_irq(port->tx_irq, port); |
1018 | 1049 | ||
1019 | arch_local_cli(); | 1050 | mn10300_serial_int_tbl[port->tx_irq].port = NULL; |
1020 | *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | 1051 | mn10300_serial_int_tbl[port->rx_irq].port = NULL; |
1021 | x = *port->rx_icr; | ||
1022 | *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | ||
1023 | x = *port->tx_icr; | ||
1024 | arch_local_sti(); | ||
1025 | } | 1052 | } |
1026 | 1053 | ||
1027 | /* | 1054 | /* |
@@ -1549,17 +1576,24 @@ static void mn10300_serial_console_write(struct console *co, | |||
1549 | { | 1576 | { |
1550 | struct mn10300_serial_port *port; | 1577 | struct mn10300_serial_port *port; |
1551 | unsigned i; | 1578 | unsigned i; |
1552 | u16 scxctr, txicr, tmp; | 1579 | u16 scxctr; |
1553 | u8 tmxmd; | 1580 | u8 tmxmd; |
1581 | unsigned long flags; | ||
1582 | int locked = 1; | ||
1554 | 1583 | ||
1555 | port = mn10300_serial_ports[co->index]; | 1584 | port = mn10300_serial_ports[co->index]; |
1556 | 1585 | ||
1586 | local_irq_save(flags); | ||
1587 | if (port->uart.sysrq) { | ||
1588 | /* mn10300_serial_interrupt() already took the lock */ | ||
1589 | locked = 0; | ||
1590 | } else if (oops_in_progress) { | ||
1591 | locked = spin_trylock(&port->uart.lock); | ||
1592 | } else | ||
1593 | spin_lock(&port->uart.lock); | ||
1594 | |||
1557 | /* firstly hijack the serial port from the "virtual DMA" controller */ | 1595 | /* firstly hijack the serial port from the "virtual DMA" controller */ |
1558 | arch_local_cli(); | 1596 | mn10300_serial_dis_tx_intr(port); |
1559 | txicr = *port->tx_icr; | ||
1560 | *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | ||
1561 | tmp = *port->tx_icr; | ||
1562 | arch_local_sti(); | ||
1563 | 1597 | ||
1564 | /* the transmitter may be disabled */ | 1598 | /* the transmitter may be disabled */ |
1565 | scxctr = *port->_control; | 1599 | scxctr = *port->_control; |
@@ -1613,10 +1647,11 @@ static void mn10300_serial_console_write(struct console *co, | |||
1613 | if (!(scxctr & SC01CTR_TXE)) | 1647 | if (!(scxctr & SC01CTR_TXE)) |
1614 | *port->_control = scxctr; | 1648 | *port->_control = scxctr; |
1615 | 1649 | ||
1616 | arch_local_cli(); | 1650 | mn10300_serial_en_tx_intr(port); |
1617 | *port->tx_icr = txicr; | 1651 | |
1618 | tmp = *port->tx_icr; | 1652 | if (locked) |
1619 | arch_local_sti(); | 1653 | spin_unlock(&port->uart.lock); |
1654 | local_irq_restore(flags); | ||
1620 | } | 1655 | } |
1621 | 1656 | ||
1622 | /* | 1657 | /* |