diff options
Diffstat (limited to 'drivers/tty/serial/pch_uart.c')
-rw-r--r-- | drivers/tty/serial/pch_uart.c | 59 |
1 files changed, 40 insertions, 19 deletions
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 4fdec6a6b758..558ce8509a9a 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c | |||
@@ -253,6 +253,9 @@ struct eg20t_port { | |||
253 | dma_addr_t rx_buf_dma; | 253 | dma_addr_t rx_buf_dma; |
254 | 254 | ||
255 | struct dentry *debugfs; | 255 | struct dentry *debugfs; |
256 | |||
257 | /* protect the eg20t_port private structure and io access to membase */ | ||
258 | spinlock_t lock; | ||
256 | }; | 259 | }; |
257 | 260 | ||
258 | /** | 261 | /** |
@@ -754,7 +757,8 @@ static void pch_dma_rx_complete(void *arg) | |||
754 | tty_flip_buffer_push(tty); | 757 | tty_flip_buffer_push(tty); |
755 | tty_kref_put(tty); | 758 | tty_kref_put(tty); |
756 | async_tx_ack(priv->desc_rx); | 759 | async_tx_ack(priv->desc_rx); |
757 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); | 760 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT | |
761 | PCH_UART_HAL_RX_ERR_INT); | ||
758 | } | 762 | } |
759 | 763 | ||
760 | static void pch_dma_tx_complete(void *arg) | 764 | static void pch_dma_tx_complete(void *arg) |
@@ -809,7 +813,8 @@ static int handle_rx_to(struct eg20t_port *priv) | |||
809 | int rx_size; | 813 | int rx_size; |
810 | int ret; | 814 | int ret; |
811 | if (!priv->start_rx) { | 815 | if (!priv->start_rx) { |
812 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); | 816 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | |
817 | PCH_UART_HAL_RX_ERR_INT); | ||
813 | return 0; | 818 | return 0; |
814 | } | 819 | } |
815 | buf = &priv->rxbuf; | 820 | buf = &priv->rxbuf; |
@@ -1058,7 +1063,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
1058 | int next = 1; | 1063 | int next = 1; |
1059 | u8 msr; | 1064 | u8 msr; |
1060 | 1065 | ||
1061 | spin_lock_irqsave(&priv->port.lock, flags); | 1066 | spin_lock_irqsave(&priv->lock, flags); |
1062 | handled = 0; | 1067 | handled = 0; |
1063 | while (next) { | 1068 | while (next) { |
1064 | iid = pch_uart_hal_get_iid(priv); | 1069 | iid = pch_uart_hal_get_iid(priv); |
@@ -1078,11 +1083,13 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
1078 | case PCH_UART_IID_RDR: /* Received Data Ready */ | 1083 | case PCH_UART_IID_RDR: /* Received Data Ready */ |
1079 | if (priv->use_dma) { | 1084 | if (priv->use_dma) { |
1080 | pch_uart_hal_disable_interrupt(priv, | 1085 | pch_uart_hal_disable_interrupt(priv, |
1081 | PCH_UART_HAL_RX_INT); | 1086 | PCH_UART_HAL_RX_INT | |
1087 | PCH_UART_HAL_RX_ERR_INT); | ||
1082 | ret = dma_handle_rx(priv); | 1088 | ret = dma_handle_rx(priv); |
1083 | if (!ret) | 1089 | if (!ret) |
1084 | pch_uart_hal_enable_interrupt(priv, | 1090 | pch_uart_hal_enable_interrupt(priv, |
1085 | PCH_UART_HAL_RX_INT); | 1091 | PCH_UART_HAL_RX_INT | |
1092 | PCH_UART_HAL_RX_ERR_INT); | ||
1086 | } else { | 1093 | } else { |
1087 | ret = handle_rx(priv); | 1094 | ret = handle_rx(priv); |
1088 | } | 1095 | } |
@@ -1116,7 +1123,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
1116 | handled |= (unsigned int)ret; | 1123 | handled |= (unsigned int)ret; |
1117 | } | 1124 | } |
1118 | 1125 | ||
1119 | spin_unlock_irqrestore(&priv->port.lock, flags); | 1126 | spin_unlock_irqrestore(&priv->lock, flags); |
1120 | return IRQ_RETVAL(handled); | 1127 | return IRQ_RETVAL(handled); |
1121 | } | 1128 | } |
1122 | 1129 | ||
@@ -1208,7 +1215,8 @@ static void pch_uart_stop_rx(struct uart_port *port) | |||
1208 | struct eg20t_port *priv; | 1215 | struct eg20t_port *priv; |
1209 | priv = container_of(port, struct eg20t_port, port); | 1216 | priv = container_of(port, struct eg20t_port, port); |
1210 | priv->start_rx = 0; | 1217 | priv->start_rx = 0; |
1211 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); | 1218 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | |
1219 | PCH_UART_HAL_RX_ERR_INT); | ||
1212 | } | 1220 | } |
1213 | 1221 | ||
1214 | /* Enable the modem status interrupts. */ | 1222 | /* Enable the modem status interrupts. */ |
@@ -1226,9 +1234,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl) | |||
1226 | unsigned long flags; | 1234 | unsigned long flags; |
1227 | 1235 | ||
1228 | priv = container_of(port, struct eg20t_port, port); | 1236 | priv = container_of(port, struct eg20t_port, port); |
1229 | spin_lock_irqsave(&port->lock, flags); | 1237 | spin_lock_irqsave(&priv->lock, flags); |
1230 | pch_uart_hal_set_break(priv, ctl); | 1238 | pch_uart_hal_set_break(priv, ctl); |
1231 | spin_unlock_irqrestore(&port->lock, flags); | 1239 | spin_unlock_irqrestore(&priv->lock, flags); |
1232 | } | 1240 | } |
1233 | 1241 | ||
1234 | /* Grab any interrupt resources and initialise any low level driver state. */ | 1242 | /* Grab any interrupt resources and initialise any low level driver state. */ |
@@ -1263,6 +1271,7 @@ static int pch_uart_startup(struct uart_port *port) | |||
1263 | break; | 1271 | break; |
1264 | case 16: | 1272 | case 16: |
1265 | fifo_size = PCH_UART_HAL_FIFO16; | 1273 | fifo_size = PCH_UART_HAL_FIFO16; |
1274 | break; | ||
1266 | case 1: | 1275 | case 1: |
1267 | default: | 1276 | default: |
1268 | fifo_size = PCH_UART_HAL_FIFO_DIS; | 1277 | fifo_size = PCH_UART_HAL_FIFO_DIS; |
@@ -1300,7 +1309,8 @@ static int pch_uart_startup(struct uart_port *port) | |||
1300 | pch_request_dma(port); | 1309 | pch_request_dma(port); |
1301 | 1310 | ||
1302 | priv->start_rx = 1; | 1311 | priv->start_rx = 1; |
1303 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); | 1312 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT | |
1313 | PCH_UART_HAL_RX_ERR_INT); | ||
1304 | uart_update_timeout(port, CS8, default_baud); | 1314 | uart_update_timeout(port, CS8, default_baud); |
1305 | 1315 | ||
1306 | return 0; | 1316 | return 0; |
@@ -1358,7 +1368,7 @@ static void pch_uart_set_termios(struct uart_port *port, | |||
1358 | stb = PCH_UART_HAL_STB1; | 1368 | stb = PCH_UART_HAL_STB1; |
1359 | 1369 | ||
1360 | if (termios->c_cflag & PARENB) { | 1370 | if (termios->c_cflag & PARENB) { |
1361 | if (!(termios->c_cflag & PARODD)) | 1371 | if (termios->c_cflag & PARODD) |
1362 | parity = PCH_UART_HAL_PARITY_ODD; | 1372 | parity = PCH_UART_HAL_PARITY_ODD; |
1363 | else | 1373 | else |
1364 | parity = PCH_UART_HAL_PARITY_EVEN; | 1374 | parity = PCH_UART_HAL_PARITY_EVEN; |
@@ -1376,7 +1386,8 @@ static void pch_uart_set_termios(struct uart_port *port, | |||
1376 | 1386 | ||
1377 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); | 1387 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); |
1378 | 1388 | ||
1379 | spin_lock_irqsave(&port->lock, flags); | 1389 | spin_lock_irqsave(&priv->lock, flags); |
1390 | spin_lock(&port->lock); | ||
1380 | 1391 | ||
1381 | uart_update_timeout(port, termios->c_cflag, baud); | 1392 | uart_update_timeout(port, termios->c_cflag, baud); |
1382 | rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); | 1393 | rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); |
@@ -1389,7 +1400,8 @@ static void pch_uart_set_termios(struct uart_port *port, | |||
1389 | tty_termios_encode_baud_rate(termios, baud, baud); | 1400 | tty_termios_encode_baud_rate(termios, baud, baud); |
1390 | 1401 | ||
1391 | out: | 1402 | out: |
1392 | spin_unlock_irqrestore(&port->lock, flags); | 1403 | spin_unlock(&port->lock); |
1404 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1393 | } | 1405 | } |
1394 | 1406 | ||
1395 | static const char *pch_uart_type(struct uart_port *port) | 1407 | static const char *pch_uart_type(struct uart_port *port) |
@@ -1538,8 +1550,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count) | |||
1538 | { | 1550 | { |
1539 | struct eg20t_port *priv; | 1551 | struct eg20t_port *priv; |
1540 | unsigned long flags; | 1552 | unsigned long flags; |
1553 | int priv_locked = 1; | ||
1554 | int port_locked = 1; | ||
1541 | u8 ier; | 1555 | u8 ier; |
1542 | int locked = 1; | ||
1543 | 1556 | ||
1544 | priv = pch_uart_ports[co->index]; | 1557 | priv = pch_uart_ports[co->index]; |
1545 | 1558 | ||
@@ -1547,12 +1560,16 @@ pch_console_write(struct console *co, const char *s, unsigned int count) | |||
1547 | 1560 | ||
1548 | local_irq_save(flags); | 1561 | local_irq_save(flags); |
1549 | if (priv->port.sysrq) { | 1562 | if (priv->port.sysrq) { |
1550 | /* serial8250_handle_port() already took the lock */ | 1563 | spin_lock(&priv->lock); |
1551 | locked = 0; | 1564 | /* serial8250_handle_port() already took the port lock */ |
1565 | port_locked = 0; | ||
1552 | } else if (oops_in_progress) { | 1566 | } else if (oops_in_progress) { |
1553 | locked = spin_trylock(&priv->port.lock); | 1567 | priv_locked = spin_trylock(&priv->lock); |
1554 | } else | 1568 | port_locked = spin_trylock(&priv->port.lock); |
1569 | } else { | ||
1570 | spin_lock(&priv->lock); | ||
1555 | spin_lock(&priv->port.lock); | 1571 | spin_lock(&priv->port.lock); |
1572 | } | ||
1556 | 1573 | ||
1557 | /* | 1574 | /* |
1558 | * First save the IER then disable the interrupts | 1575 | * First save the IER then disable the interrupts |
@@ -1570,8 +1587,10 @@ pch_console_write(struct console *co, const char *s, unsigned int count) | |||
1570 | wait_for_xmitr(priv, BOTH_EMPTY); | 1587 | wait_for_xmitr(priv, BOTH_EMPTY); |
1571 | iowrite8(ier, priv->membase + UART_IER); | 1588 | iowrite8(ier, priv->membase + UART_IER); |
1572 | 1589 | ||
1573 | if (locked) | 1590 | if (port_locked) |
1574 | spin_unlock(&priv->port.lock); | 1591 | spin_unlock(&priv->port.lock); |
1592 | if (priv_locked) | ||
1593 | spin_unlock(&priv->lock); | ||
1575 | local_irq_restore(flags); | 1594 | local_irq_restore(flags); |
1576 | } | 1595 | } |
1577 | 1596 | ||
@@ -1669,6 +1688,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, | |||
1669 | pci_enable_msi(pdev); | 1688 | pci_enable_msi(pdev); |
1670 | pci_set_master(pdev); | 1689 | pci_set_master(pdev); |
1671 | 1690 | ||
1691 | spin_lock_init(&priv->lock); | ||
1692 | |||
1672 | iobase = pci_resource_start(pdev, 0); | 1693 | iobase = pci_resource_start(pdev, 0); |
1673 | mapbase = pci_resource_start(pdev, 1); | 1694 | mapbase = pci_resource_start(pdev, 1); |
1674 | priv->mapbase = mapbase; | 1695 | priv->mapbase = mapbase; |