aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel/mn10300-serial.c
diff options
context:
space:
mode:
authorMark Salter <msalter@redhat.com>2012-12-12 10:36:38 -0500
committerDavid Howells <dhowells@redhat.com>2012-12-12 10:46:14 -0500
commit8f0bcbcab016324c2a3ba4cc715e8e523c29a578 (patch)
tree8833a5b7f169942e41ba907c54ba817b64be4ba2 /arch/mn10300/kernel/mn10300-serial.c
parent8d160027ff234bddea627ba54c2b85efa1884867 (diff)
MN10300: fix SMP synchronization between txdma and serial driver
The SoC serial port driver uses a high priority interrupt to handle tx of characters in the tx ring buffer. The driver needs to disable/enable this IRQ from outside of irq context. The original code to do this is not foolproof on SMP machines because the IRQ running on one core could still access the serial port for a short time after the driver running on another core disables the interrupt. This patch adds a flag to tell the IRQ handler that the driver wants to disable the interrupt. After seeing the flag, the IRQ handler will immediately disable the interrupt and exit. After setting the flag, the driver will wait for interrupt to be disabled by the IRQ handler. Signed-off-by: Mark Salter <msalter@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'arch/mn10300/kernel/mn10300-serial.c')
-rw-r--r--arch/mn10300/kernel/mn10300-serial.c121
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
445static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port) 445static 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
456static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port) 475static 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
468static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port) 496static 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 */
995static void mn10300_serial_shutdown(struct uart_port *_port) 1018static 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/*