From: Greg Kroah-Hartman Date: Wed, 3 Apr 2019 14:11:21 +0000 (+0200) Subject: 4.19-stable patches X-Git-Tag: v4.9.168~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a220fbe58dd2175c9f23c552969c7d89fecfd82e;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-stable patches added patches: ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch tty-serial-atmel-add-is_half_duplex-helper.patch tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch --- diff --git a/queue-4.19/ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch b/queue-4.19/ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch new file mode 100644 index 00000000000..47ca58708df --- /dev/null +++ b/queue-4.19/ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch @@ -0,0 +1,163 @@ +From 5e86bdda41534e17621d5a071b294943cae4376e Mon Sep 17 00:00:00 2001 +From: "zhangyi (F)" +Date: Sat, 23 Mar 2019 11:56:01 -0400 +Subject: ext4: cleanup bh release code in ext4_ind_remove_space() + +From: zhangyi (F) + +commit 5e86bdda41534e17621d5a071b294943cae4376e upstream. + +Currently, we are releasing the indirect buffer where we are done with +it in ext4_ind_remove_space(), so we can see the brelse() and +BUFFER_TRACE() everywhere. It seems fragile and hard to read, and we +may probably forget to release the buffer some day. This patch cleans +up the code by putting of the code which releases the buffers to the +end of the function. + +Signed-off-by: zhangyi (F) +Signed-off-by: Theodore Ts'o +Reviewed-by: Jan Kara +Cc: Jari Ruusu +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ext4/indirect.c | 47 ++++++++++++++++++++++------------------------- + 1 file changed, 22 insertions(+), 25 deletions(-) + +--- a/fs/ext4/indirect.c ++++ b/fs/ext4/indirect.c +@@ -1219,6 +1219,7 @@ int ext4_ind_remove_space(handle_t *hand + ext4_lblk_t offsets[4], offsets2[4]; + Indirect chain[4], chain2[4]; + Indirect *partial, *partial2; ++ Indirect *p = NULL, *p2 = NULL; + ext4_lblk_t max_block; + __le32 nr = 0, nr2 = 0; + int n = 0, n2 = 0; +@@ -1260,7 +1261,7 @@ int ext4_ind_remove_space(handle_t *hand + } + + +- partial = ext4_find_shared(inode, n, offsets, chain, &nr); ++ partial = p = ext4_find_shared(inode, n, offsets, chain, &nr); + if (nr) { + if (partial == chain) { + /* Shared branch grows from the inode */ +@@ -1285,13 +1286,11 @@ int ext4_ind_remove_space(handle_t *hand + partial->p + 1, + (__le32 *)partial->bh->b_data+addr_per_block, + (chain+n-1) - partial); +- BUFFER_TRACE(partial->bh, "call brelse"); +- brelse(partial->bh); + partial--; + } + + end_range: +- partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); ++ partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); + if (nr2) { + if (partial2 == chain2) { + /* +@@ -1321,16 +1320,14 @@ end_range: + (__le32 *)partial2->bh->b_data, + partial2->p, + (chain2+n2-1) - partial2); +- BUFFER_TRACE(partial2->bh, "call brelse"); +- brelse(partial2->bh); + partial2--; + } + goto do_indirects; + } + + /* Punch happened within the same level (n == n2) */ +- partial = ext4_find_shared(inode, n, offsets, chain, &nr); +- partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); ++ partial = p = ext4_find_shared(inode, n, offsets, chain, &nr); ++ partial2 = p2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); + + /* Free top, but only if partial2 isn't its subtree. */ + if (nr) { +@@ -1387,15 +1384,7 @@ end_range: + partial->p + 1, + partial2->p, + (chain+n-1) - partial); +- while (partial > chain) { +- BUFFER_TRACE(partial->bh, "call brelse"); +- brelse(partial->bh); +- } +- while (partial2 > chain2) { +- BUFFER_TRACE(partial2->bh, "call brelse"); +- brelse(partial2->bh); +- } +- return 0; ++ goto cleanup; + } + + /* +@@ -1410,8 +1399,6 @@ end_range: + partial->p + 1, + (__le32 *)partial->bh->b_data+addr_per_block, + (chain+n-1) - partial); +- BUFFER_TRACE(partial->bh, "call brelse"); +- brelse(partial->bh); + partial--; + } + if (partial2 > chain2 && depth2 <= depth) { +@@ -1419,11 +1406,21 @@ end_range: + (__le32 *)partial2->bh->b_data, + partial2->p, + (chain2+n2-1) - partial2); +- BUFFER_TRACE(partial2->bh, "call brelse"); +- brelse(partial2->bh); + partial2--; + } + } ++ ++cleanup: ++ while (p && p > chain) { ++ BUFFER_TRACE(p->bh, "call brelse"); ++ brelse(p->bh); ++ p--; ++ } ++ while (p2 && p2 > chain2) { ++ BUFFER_TRACE(p2->bh, "call brelse"); ++ brelse(p2->bh); ++ p2--; ++ } + return 0; + + do_indirects: +@@ -1431,7 +1428,7 @@ do_indirects: + switch (offsets[0]) { + default: + if (++n >= n2) +- return 0; ++ break; + nr = i_data[EXT4_IND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); +@@ -1439,7 +1436,7 @@ do_indirects: + } + case EXT4_IND_BLOCK: + if (++n >= n2) +- return 0; ++ break; + nr = i_data[EXT4_DIND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); +@@ -1447,7 +1444,7 @@ do_indirects: + } + case EXT4_DIND_BLOCK: + if (++n >= n2) +- return 0; ++ break; + nr = i_data[EXT4_TIND_BLOCK]; + if (nr) { + ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); +@@ -1456,5 +1453,5 @@ do_indirects: + case EXT4_TIND_BLOCK: + ; + } +- return 0; ++ goto cleanup; + } diff --git a/queue-4.19/series b/queue-4.19/series index e7069e23242..482200e0e0e 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -1 +1,4 @@ arm64-debug-don-t-propagate-unknown-far-into-si_code-for-debug-signals.patch +ext4-cleanup-bh-release-code-in-ext4_ind_remove_space.patch +tty-serial-atmel-add-is_half_duplex-helper.patch +tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch diff --git a/queue-4.19/tty-serial-atmel-add-is_half_duplex-helper.patch b/queue-4.19/tty-serial-atmel-add-is_half_duplex-helper.patch new file mode 100644 index 00000000000..1fcd1d66d07 --- /dev/null +++ b/queue-4.19/tty-serial-atmel-add-is_half_duplex-helper.patch @@ -0,0 +1,80 @@ +From f3040983132bf3477acd45d2452a906e67c2fec9 Mon Sep 17 00:00:00 2001 +From: Razvan Stefanescu +Date: Tue, 19 Mar 2019 15:20:34 +0200 +Subject: tty/serial: atmel: Add is_half_duplex helper + +From: Razvan Stefanescu + +commit f3040983132bf3477acd45d2452a906e67c2fec9 upstream. + +Use a helper function to check that a port needs to use half duplex +communication, replacing several occurrences of multi-line bit checking. + +Fixes: b389f173aaa1 ("tty/serial: atmel: RS485 half duplex w/DMA: enable RX after TX is done") +Cc: stable +Signed-off-by: Razvan Stefanescu +Acked-by: Richard Genoud +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/tty/serial/atmel_serial.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -225,6 +225,12 @@ static inline void atmel_uart_write_char + __raw_writeb(value, port->membase + ATMEL_US_THR); + } + ++static inline int atmel_uart_is_half_duplex(struct uart_port *port) ++{ ++ return (port->rs485.flags & SER_RS485_ENABLED) && ++ !(port->rs485.flags & SER_RS485_RX_DURING_TX); ++} ++ + #ifdef CONFIG_SERIAL_ATMEL_PDC + static bool atmel_use_pdc_rx(struct uart_port *port) + { +@@ -481,9 +487,9 @@ static void atmel_stop_tx(struct uart_po + /* Disable interrupts */ + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); + +- if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ++ if (atmel_uart_is_half_duplex(port)) + atmel_start_rx(port); ++ + } + + /* +@@ -500,8 +506,7 @@ static void atmel_start_tx(struct uart_p + return; + + if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) +- if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ++ if (atmel_uart_is_half_duplex(port)) + atmel_stop_rx(port); + + if (atmel_use_pdc_tx(port)) +@@ -799,8 +804,7 @@ static void atmel_complete_tx_dma(void * + */ + if (!uart_circ_empty(xmit)) + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); +- else if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { ++ else if (atmel_uart_is_half_duplex(port)) { + /* DMA done, stop TX, start RX for RS485 */ + atmel_start_rx(port); + } +@@ -1377,8 +1381,7 @@ static void atmel_tx_pdc(struct uart_por + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); + } else { +- if ((port->rs485.flags & SER_RS485_ENABLED) && +- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { ++ if (atmel_uart_is_half_duplex(port)) { + /* DMA done, stop TX, start RX for RS485 */ + atmel_start_rx(port); + } diff --git a/queue-4.19/tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch b/queue-4.19/tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch new file mode 100644 index 00000000000..8bd07192f14 --- /dev/null +++ b/queue-4.19/tty-serial-atmel-rs485-hd-w-dma-enable-rx-after-tx-is-stopped.patch @@ -0,0 +1,79 @@ +From 69646d7a3689fbe1a65ae90397d22ac3f1b8d40f Mon Sep 17 00:00:00 2001 +From: Razvan Stefanescu +Date: Tue, 19 Mar 2019 15:20:35 +0200 +Subject: tty/serial: atmel: RS485 HD w/DMA: enable RX after TX is stopped + +From: Razvan Stefanescu + +commit 69646d7a3689fbe1a65ae90397d22ac3f1b8d40f upstream. + +In half-duplex operation, RX should be started after TX completes. + +If DMA is used, there is a case when the DMA transfer completes but the +TX FIFO is not emptied, so the RX cannot be restarted just yet. + +Use a boolean variable to store this state and rearm TX interrupt mask +to be signaled again that the transfer finished. In interrupt transmit +handler this variable is used to start RX. A warning message is generated +if RX is activated before TX fifo is cleared. + +Fixes: b389f173aaa1 ("tty/serial: atmel: RS485 half duplex w/DMA: enable +RX after TX is done") +Signed-off-by: Razvan Stefanescu +Acked-by: Richard Genoud +Cc: stable +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/atmel_serial.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -163,6 +163,8 @@ struct atmel_uart_port { + unsigned int pending_status; + spinlock_t lock_suspended; + ++ bool hd_start_rx; /* can start RX during half-duplex operation */ ++ + #ifdef CONFIG_PM + struct { + u32 cr; +@@ -805,8 +807,13 @@ static void atmel_complete_tx_dma(void * + if (!uart_circ_empty(xmit)) + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); + else if (atmel_uart_is_half_duplex(port)) { +- /* DMA done, stop TX, start RX for RS485 */ +- atmel_start_rx(port); ++ /* ++ * DMA done, re-enable TXEMPTY and signal that we can stop ++ * TX and start RX for RS485 ++ */ ++ atmel_port->hd_start_rx = true; ++ atmel_uart_writel(port, ATMEL_US_IER, ++ atmel_port->tx_done_mask); + } + + spin_unlock_irqrestore(&port->lock, flags); +@@ -1252,9 +1259,20 @@ atmel_handle_transmit(struct uart_port * + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (pending & atmel_port->tx_done_mask) { +- /* Either PDC or interrupt transmission */ + atmel_uart_writel(port, ATMEL_US_IDR, + atmel_port->tx_done_mask); ++ ++ /* Start RX if flag was set and FIFO is empty */ ++ if (atmel_port->hd_start_rx) { ++ if (!(atmel_uart_readl(port, ATMEL_US_CSR) ++ & ATMEL_US_TXEMPTY)) ++ dev_warn(port->dev, "Should start RX, but TX fifo is not empty\n"); ++ ++ atmel_port->hd_start_rx = false; ++ atmel_start_rx(port); ++ return; ++ } ++ + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); + } + }