aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Ferre <nicolas.ferre@atmel.com>2016-06-26 03:44:49 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-06-26 13:57:13 -0400
commit98f2082c3ac4042189723c120553310700b583bb (patch)
tree8b1c5815105f03574a14f36be1f44c6ddbda40d6
parent5fd2b6ee7a319e0955acff96948fae57321b1f5a (diff)
tty/serial: atmel: enforce tasklet init and termination sequences
As some race conditions are identified in the termination process of tasklets, enforce the atmel_shutdown() sequence. This way we make sure that no new tasklets or software timer are scheduled during shutdown process. An atomic flag is positioned to give this information throughout the code. We also remove tasklet_disable() calls that were leading to deadlocks while stopping the driver. A simpler init/kill sequence is used. Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/atmel_serial.c61
1 files changed, 38 insertions, 23 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index f887c1df23e6..2eaa18ddef61 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -153,6 +153,7 @@ struct atmel_uart_port {
153 struct scatterlist sg_rx; 153 struct scatterlist sg_rx;
154 struct tasklet_struct tasklet_rx; 154 struct tasklet_struct tasklet_rx;
155 struct tasklet_struct tasklet_tx; 155 struct tasklet_struct tasklet_tx;
156 atomic_t tasklet_shutdown;
156 unsigned int irq_status_prev; 157 unsigned int irq_status_prev;
157 unsigned int tx_len; 158 unsigned int tx_len;
158 159
@@ -286,6 +287,13 @@ static bool atmel_use_fifo(struct uart_port *port)
286 return atmel_port->fifo_size; 287 return atmel_port->fifo_size;
287} 288}
288 289
290static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port,
291 struct tasklet_struct *t)
292{
293 if (!atomic_read(&atmel_port->tasklet_shutdown))
294 tasklet_schedule(t);
295}
296
289static unsigned int atmel_get_lines_status(struct uart_port *port) 297static unsigned int atmel_get_lines_status(struct uart_port *port)
290{ 298{
291 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 299 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -717,7 +725,7 @@ static void atmel_rx_chars(struct uart_port *port)
717 status = atmel_uart_readl(port, ATMEL_US_CSR); 725 status = atmel_uart_readl(port, ATMEL_US_CSR);
718 } 726 }
719 727
720 tasklet_schedule(&atmel_port->tasklet_rx); 728 atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
721} 729}
722 730
723/* 731/*
@@ -788,7 +796,7 @@ static void atmel_complete_tx_dma(void *arg)
788 * remaining data from the beginning of xmit->buf to xmit->head. 796 * remaining data from the beginning of xmit->buf to xmit->head.
789 */ 797 */
790 if (!uart_circ_empty(xmit)) 798 if (!uart_circ_empty(xmit))
791 tasklet_schedule(&atmel_port->tasklet_tx); 799 atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
792 800
793 spin_unlock_irqrestore(&port->lock, flags); 801 spin_unlock_irqrestore(&port->lock, flags);
794} 802}
@@ -973,7 +981,7 @@ static void atmel_complete_rx_dma(void *arg)
973 struct uart_port *port = arg; 981 struct uart_port *port = arg;
974 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 982 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
975 983
976 tasklet_schedule(&atmel_port->tasklet_rx); 984 atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
977} 985}
978 986
979static void atmel_release_rx_dma(struct uart_port *port) 987static void atmel_release_rx_dma(struct uart_port *port)
@@ -1013,7 +1021,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
1013 if (dmastat == DMA_ERROR) { 1021 if (dmastat == DMA_ERROR) {
1014 dev_dbg(port->dev, "Get residue error, restart tasklet\n"); 1022 dev_dbg(port->dev, "Get residue error, restart tasklet\n");
1015 atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); 1023 atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT);
1016 tasklet_schedule(&atmel_port->tasklet_rx); 1024 atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
1017 return; 1025 return;
1018 } 1026 }
1019 1027
@@ -1167,8 +1175,11 @@ static void atmel_uart_timer_callback(unsigned long data)
1167 struct uart_port *port = (void *)data; 1175 struct uart_port *port = (void *)data;
1168 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 1176 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
1169 1177
1170 tasklet_schedule(&atmel_port->tasklet_rx); 1178 if (!atomic_read(&atmel_port->tasklet_shutdown)) {
1171 mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); 1179 tasklet_schedule(&atmel_port->tasklet_rx);
1180 mod_timer(&atmel_port->uart_timer,
1181 jiffies + uart_poll_timeout(port));
1182 }
1172} 1183}
1173 1184
1174/* 1185/*
@@ -1190,7 +1201,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
1190 if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { 1201 if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
1191 atmel_uart_writel(port, ATMEL_US_IDR, 1202 atmel_uart_writel(port, ATMEL_US_IDR,
1192 (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); 1203 (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT));
1193 tasklet_schedule(&atmel_port->tasklet_rx); 1204 atmel_tasklet_schedule(atmel_port,
1205 &atmel_port->tasklet_rx);
1194 } 1206 }
1195 1207
1196 if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | 1208 if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
@@ -1202,7 +1214,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
1202 if (pending & ATMEL_US_TIMEOUT) { 1214 if (pending & ATMEL_US_TIMEOUT) {
1203 atmel_uart_writel(port, ATMEL_US_IDR, 1215 atmel_uart_writel(port, ATMEL_US_IDR,
1204 ATMEL_US_TIMEOUT); 1216 ATMEL_US_TIMEOUT);
1205 tasklet_schedule(&atmel_port->tasklet_rx); 1217 atmel_tasklet_schedule(atmel_port,
1218 &atmel_port->tasklet_rx);
1206 } 1219 }
1207 } 1220 }
1208 1221
@@ -1232,7 +1245,7 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending)
1232 /* Either PDC or interrupt transmission */ 1245 /* Either PDC or interrupt transmission */
1233 atmel_uart_writel(port, ATMEL_US_IDR, 1246 atmel_uart_writel(port, ATMEL_US_IDR,
1234 atmel_port->tx_done_mask); 1247 atmel_port->tx_done_mask);
1235 tasklet_schedule(&atmel_port->tasklet_tx); 1248 atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
1236 } 1249 }
1237} 1250}
1238 1251
@@ -1793,8 +1806,11 @@ static int atmel_startup(struct uart_port *port)
1793 return retval; 1806 return retval;
1794 } 1807 }
1795 1808
1796 tasklet_enable(&atmel_port->tasklet_rx); 1809 atomic_set(&atmel_port->tasklet_shutdown, 0);
1797 tasklet_enable(&atmel_port->tasklet_tx); 1810 tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func,
1811 (unsigned long)port);
1812 tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func,
1813 (unsigned long)port);
1798 1814
1799 /* 1815 /*
1800 * Initialize DMA (if necessary) 1816 * Initialize DMA (if necessary)
@@ -1913,31 +1929,36 @@ static void atmel_shutdown(struct uart_port *port)
1913{ 1929{
1914 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 1930 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
1915 1931
1932 /* Disable interrupts at device level */
1933 atmel_uart_writel(port, ATMEL_US_IDR, -1);
1934
1935 /* Prevent spurious interrupts from scheduling the tasklet */
1936 atomic_inc(&atmel_port->tasklet_shutdown);
1937
1916 /* 1938 /*
1917 * Prevent any tasklets being scheduled during 1939 * Prevent any tasklets being scheduled during
1918 * cleanup 1940 * cleanup
1919 */ 1941 */
1920 del_timer_sync(&atmel_port->uart_timer); 1942 del_timer_sync(&atmel_port->uart_timer);
1921 1943
1944 /* Make sure that no interrupt is on the fly */
1945 synchronize_irq(port->irq);
1946
1922 /* 1947 /*
1923 * Clear out any scheduled tasklets before 1948 * Clear out any scheduled tasklets before
1924 * we destroy the buffers 1949 * we destroy the buffers
1925 */ 1950 */
1926 tasklet_disable(&atmel_port->tasklet_rx);
1927 tasklet_disable(&atmel_port->tasklet_tx);
1928 tasklet_kill(&atmel_port->tasklet_rx); 1951 tasklet_kill(&atmel_port->tasklet_rx);
1929 tasklet_kill(&atmel_port->tasklet_tx); 1952 tasklet_kill(&atmel_port->tasklet_tx);
1930 1953
1931 /* 1954 /*
1932 * Ensure everything is stopped and 1955 * Ensure everything is stopped and
1933 * disable all interrupts, port and break condition. 1956 * disable port and break condition.
1934 */ 1957 */
1935 atmel_stop_rx(port); 1958 atmel_stop_rx(port);
1936 atmel_stop_tx(port); 1959 atmel_stop_tx(port);
1937 1960
1938 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); 1961 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA);
1939 atmel_uart_writel(port, ATMEL_US_IDR, -1);
1940
1941 1962
1942 /* 1963 /*
1943 * Shut-down the DMA. 1964 * Shut-down the DMA.
@@ -2321,13 +2342,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
2321 port->irq = pdev->resource[1].start; 2342 port->irq = pdev->resource[1].start;
2322 port->rs485_config = atmel_config_rs485; 2343 port->rs485_config = atmel_config_rs485;
2323 2344
2324 tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func,
2325 (unsigned long)port);
2326 tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func,
2327 (unsigned long)port);
2328 tasklet_disable(&atmel_port->tasklet_rx);
2329 tasklet_disable(&atmel_port->tasklet_tx);
2330
2331 memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); 2345 memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
2332 2346
2333 if (pdata && pdata->regs) { 2347 if (pdata && pdata->regs) {
@@ -2712,6 +2726,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
2712 atmel_port->uart.line = ret; 2726 atmel_port->uart.line = ret;
2713 atmel_serial_probe_fifos(atmel_port, pdev); 2727 atmel_serial_probe_fifos(atmel_port, pdev);
2714 2728
2729 atomic_set(&atmel_port->tasklet_shutdown, 0);
2715 spin_lock_init(&atmel_port->lock_suspended); 2730 spin_lock_init(&atmel_port->lock_suspended);
2716 2731
2717 ret = atmel_init_port(atmel_port, pdev); 2732 ret = atmel_init_port(atmel_port, pdev);