--- /dev/null
+From 5e86bdda41534e17621d5a071b294943cae4376e Mon Sep 17 00:00:00 2001
+From: "zhangyi (F)" <yi.zhang@huawei.com>
+Date: Sat, 23 Mar 2019 11:56:01 -0400
+Subject: ext4: cleanup bh release code in ext4_ind_remove_space()
+
+From: zhangyi (F) <yi.zhang@huawei.com>
+
+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) <yi.zhang@huawei.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Cc: Jari Ruusu <jari.ruusu@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+ }
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
--- /dev/null
+From f3040983132bf3477acd45d2452a906e67c2fec9 Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@microchip.com>
+Date: Tue, 19 Mar 2019 15:20:34 +0200
+Subject: tty/serial: atmel: Add is_half_duplex helper
+
+From: Razvan Stefanescu <razvan.stefanescu@microchip.com>
+
+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 <stable@vger.kernel.org>
+Signed-off-by: Razvan Stefanescu <razvan.stefanescu@microchip.com>
+Acked-by: Richard Genoud <richard.genoud@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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);
+ }
--- /dev/null
+From 69646d7a3689fbe1a65ae90397d22ac3f1b8d40f Mon Sep 17 00:00:00 2001
+From: Razvan Stefanescu <razvan.stefanescu@microchip.com>
+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 <razvan.stefanescu@microchip.com>
+
+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 <razvan.stefanescu@microchip.com>
+Acked-by: Richard Genoud <richard.genoud@gmail.com>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
+ }
+ }