Skip to contentSkip to conversation

serial: stm32: Merge hard IRQ and threaded IRQ handling into single IRQ handler

PATCH Superseded Marek Vasut 4 participants 13 messages Dec 16, 2022 – Jan 12, 2023

Subsystems (2)

v3 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v3 1/1 serial: stm32: Merge hard IRQ and threaded IRQ handling into single IRQ handler

Requesting an interrupt with IRQF_ONESHOT will run the primary handler in the hard-IRQ context even in the force-threaded mode. The force-threaded mode is used by PREEMPT_RT in order to avoid acquiring sleeping locks (spinlock_t) in hard-IRQ context. This combination makes it impossible and leads to "sleeping while atomic" warnings.

Use one interrupt handler for both handlers (primary and secondary) and drop the IRQF_ONESHOT flag which is not needed.

Fixes e359b4411c283 ("serial: stm32: fix threaded interrupt handling")

---
Cc: Alexandre Torgue <[email protected]>
Cc: Erwan Le Ray <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Jiri Slaby <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Valentin Caron <[email protected]>
Cc: [email protected]
Cc: [email protected]
To: [email protected]
---
V2: - Update patch subject, was:
serial: stm32: Move hard IRQ handling to threaded interrupt context
- Use request_irq() instead, rename the IRQ handler function
V3: - Update the commit message per suggestion from Sebastian
- Add RB from Sebastian
- Add Fixes tag

---
 drivers/tty/serial/stm32-usart.c | 29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)
drivers/tty/serial/stm32-usart.c +7 -22
index dfdbcf092facc..bbbab8dc2bfa9 100644
@@ -752,8 +752,9 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
 	struct tty_port *tport = &port->state->port;
 	struct stm32_port *stm32_port = to_stm32_port(port);
 	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
-	u32 sr;
+	unsigned long flags;
 	unsigned int size;
+	u32 sr;
 
 	sr = readl_relaxed(port->membase + ofs->isr);
 
@@ -793,27 +794,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
 	}
 
 	if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
-		spin_lock(&port->lock);
+		spin_lock_irqsave(&port->lock, flags);
 		stm32_usart_transmit_chars(port);
-		spin_unlock(&port->lock);
+		spin_unlock_irqrestore(&port->lock, flags);
 	}
 
-	if (stm32_usart_rx_dma_enabled(port))
-		return IRQ_WAKE_THREAD;
-	else
-		return IRQ_HANDLED;
-}
-
-static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
-{
-	struct uart_port *port = ptr;
-	struct tty_port *tport = &port->state->port;
-	struct stm32_port *stm32_port = to_stm32_port(port);
-	unsigned int size;
-	unsigned long flags;
-
 	/* Receiver timeout irq for DMA RX */
-	if (!stm32_port->throttled) {
+	if (stm32_usart_rx_dma_enabled(port) && !stm32_port->throttled) {
 		spin_lock_irqsave(&port->lock, flags);
 		size = stm32_usart_receive_chars(port, false);
 		uart_unlock_and_check_sysrq_irqrestore(port, flags);
@@ -1016,10 +1003,8 @@ static int stm32_usart_startup(struct uart_port *port)
 	u32 val;
 	int ret;
 
-	ret = request_threaded_irq(port->irq, stm32_usart_interrupt,
-				   stm32_usart_threaded_interrupt,
-				   IRQF_ONESHOT | IRQF_NO_SUSPEND,
-				   name, port);
+	ret = request_irq(port->irq, stm32_usart_interrupt,
+			  IRQF_NO_SUSPEND, name, port);
 	if (ret)
 		return ret;
 
Signature · 1 line
2.35.1
#1 lore raw
Quoted 10 lines · Marek Vasut

Requesting an interrupt with IRQF_ONESHOT will run the primary handler in the hard-IRQ context even in the force-threaded mode. The force-threaded mode is used by PREEMPT_RT in order to avoid acquiring sleeping locks (spinlock_t) in hard-IRQ context. This combination makes it impossible and leads to "sleeping while atomic" warnings.

Use one interrupt handler for both handlers (primary and secondary) and drop the IRQF_ONESHOT flag which is not needed.

Fixes e359b4411c283 ("serial: stm32: fix threaded interrupt handling")

I don't think a Fixes tag is warranted as this is only needed due to this undocumented quirk of PREEMPT_RT.

And this should not be backported in any case.

Quoted 41 lines

---
Cc: Alexandre Torgue <[email protected]>
Cc: Erwan Le Ray <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Jiri Slaby <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Valentin Caron <[email protected]>
Cc: [email protected]
Cc: [email protected]
To: [email protected]
---
V2: - Update patch subject, was:
serial: stm32: Move hard IRQ handling to threaded interrupt context
- Use request_irq() instead, rename the IRQ handler function
V3: - Update the commit message per suggestion from Sebastian
- Add RB from Sebastian
- Add Fixes tag

---
 drivers/tty/serial/stm32-usart.c | 29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)
drivers/tty/serial/stm32-usart.c +2 -1
index dfdbcf092facc..bbbab8dc2bfa9 100644
@@ -752,8 +752,9 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
 	struct tty_port *tport = &port->state->port;
 	struct stm32_port *stm32_port = to_stm32_port(port);
 	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
-	u32 sr;
+	unsigned long flags;
 	unsigned int size;
+	u32 sr;
 
 	sr = readl_relaxed(port->membase + ofs->isr);
 

drivers/tty/serial/stm32-usart.c static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) · line 799

Quoted 8 lines
drivers/tty/serial/stm32-usart.c +2 -2
@@ -793,27 +794,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
 	}
 
 	if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
-		spin_lock(&port->lock);
+		spin_lock_irqsave(&port->lock, flags);
 		stm32_usart_transmit_chars(port);
-		spin_unlock(&port->lock);
+		spin_unlock_irqrestore(&port->lock, flags);

This is not needed as the handler runs with interrupts disabled.

Quoted 10 lines
drivers/tty/serial/stm32-usart.c +0 -8
 	}
 
-	if (stm32_usart_rx_dma_enabled(port))
-		return IRQ_WAKE_THREAD;
-	else
-		return IRQ_HANDLED;
-}
-
-static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
-{

drivers/tty/serial/stm32-usart.c static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) · line 804

Quoted 10 lines
drivers/tty/serial/stm32-usart.c +1 -7
-	struct uart_port *port = ptr;
-	struct tty_port *tport = &port->state->port;
-	struct stm32_port *stm32_port = to_stm32_port(port);
-	unsigned int size;
-	unsigned long flags;
-
 	/* Receiver timeout irq for DMA RX */
-	if (!stm32_port->throttled) {
+	if (stm32_usart_rx_dma_enabled(port) && !stm32_port->throttled) {
 		spin_lock_irqsave(&port->lock, flags);

But you could change this to spin_lock() now.

Quoted 4 lines
drivers/tty/serial/stm32-usart.c +0 -0
 		size = stm32_usart_receive_chars(port, false);
 		uart_unlock_and_check_sysrq_irqrestore(port, flags);
@@ -1016,10 +1003,8 @@ static int stm32_usart_startup(struct uart_port *port)
 	u32 val;

drivers/tty/serial/stm32-usart.c static int stm32_usart_startup(struct uart_port *port) · line 1009

Quoted 10 lines
drivers/tty/serial/stm32-usart.c +2 -4
 	int ret;
 
-	ret = request_threaded_irq(port->irq, stm32_usart_interrupt,
-				   stm32_usart_threaded_interrupt,
-				   IRQF_ONESHOT | IRQF_NO_SUSPEND,
-				   name, port);
+	ret = request_irq(port->irq, stm32_usart_interrupt,
+			  IRQF_NO_SUSPEND, name, port);
 	if (ret)
 		return ret;

You should also remove

	/*
	 * Using DMA and threaded handler for the console could lead to
	 * deadlocks.
	 */
	if (uart_console(port))
		return -ENODEV;

from stm32_usart_of_dma_rx_probe() when removing the threaded handler.

Johan

#2 lore raw

On 12/27/22 15:56, Johan Hovold wrote:

[...]

Quoted 11 lines

drivers/tty/serial/stm32-usart.c static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) · line 799

Quoted 9 lines
drivers/tty/serial/stm32-usart.c +2 -2
@@ -793,27 +794,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
  	}
 
  	if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
-		spin_lock(&port->lock);
+		spin_lock_irqsave(&port->lock, flags);
  		stm32_usart_transmit_chars(port);
-		spin_unlock(&port->lock);
+		spin_unlock_irqrestore(&port->lock, flags);

This is not needed as the handler runs with interrupts disabled.

On SMP system, another thread on another core can call stm32_usart_transmit_chars() . I don't think removing the locking is correct ?

Quoted 23 lines
Quoted 11 lines
drivers/tty/serial/stm32-usart.c +0 -8
  	}
 
-	if (stm32_usart_rx_dma_enabled(port))
-		return IRQ_WAKE_THREAD;
-	else
-		return IRQ_HANDLED;
-}
-
-static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
-{

drivers/tty/serial/stm32-usart.c static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) · line 804

Quoted 10 lines
drivers/tty/serial/stm32-usart.c +1 -7
-	struct uart_port *port = ptr;
-	struct tty_port *tport = &port->state->port;
-	struct stm32_port *stm32_port = to_stm32_port(port);
-	unsigned int size;
-	unsigned long flags;
-
  	/* Receiver timeout irq for DMA RX */
-	if (!stm32_port->throttled) {
+	if (stm32_usart_rx_dma_enabled(port) && !stm32_port->throttled) {
  		spin_lock_irqsave(&port->lock, flags);

But you could change this to spin_lock() now.

[...]

#3 lore raw
Quoted 16 lines · Marek Vasut

On 12/27/22 15:56, Johan Hovold wrote:

[...]

Quoted 11 lines

drivers/tty/serial/stm32-usart.c static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) · line 799

Quoted 9 lines
drivers/tty/serial/stm32-usart.c +2 -2
@@ -793,27 +794,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
  	}
 
  	if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
-		spin_lock(&port->lock);
+		spin_lock_irqsave(&port->lock, flags);
  		stm32_usart_transmit_chars(port);
-		spin_unlock(&port->lock);
+		spin_unlock_irqrestore(&port->lock, flags);

This is not needed as the handler runs with interrupts disabled.

Quoted 3 lines

On SMP system, another thread on another core can call stm32_usart_transmit_chars() . I don't think removing the locking is correct ?

I didn't say that you should remove the locking, which is very much needed. There's just no need to disable interrupts in a (non-threaded) interrupt handler as that has already been done by IRQ core (and, yes, that is also the case with forced threading).

Johan

#4 lore raw
Quoted 17 lines · Johan Hovold
Quoted 16 lines · Marek Vasut

On 12/27/22 15:56, Johan Hovold wrote:

[...]

Quoted 11 lines

drivers/tty/serial/stm32-usart.c static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) · line 799

Quoted 9 lines
drivers/tty/serial/stm32-usart.c +2 -2
@@ -793,27 +794,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
   	}
 
   	if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
-		spin_lock(&port->lock);
+		spin_lock_irqsave(&port->lock, flags);
   		stm32_usart_transmit_chars(port);
-		spin_unlock(&port->lock);
+		spin_unlock_irqrestore(&port->lock, flags);

This is not needed as the handler runs with interrupts disabled.

Quoted 8 lines
Quoted 3 lines

On SMP system, another thread on another core can call stm32_usart_transmit_chars() . I don't think removing the locking is correct ?

I didn't say that you should remove the locking, which is very much needed. There's just no need to disable interrupts in a (non-threaded) interrupt handler as that has already been done by IRQ core (and, yes, that is also the case with forced threading).

Ah, understood.

#5 lore raw
In reply to Johan Hovold
Quoted 7 lines · Johan Hovold
Quoted 6 lines · Marek Vasut

Requesting an interrupt with IRQF_ONESHOT will run the primary handler in the hard-IRQ context even in the force-threaded mode. The force-threaded mode is used by PREEMPT_RT in order to avoid acquiring sleeping locks (spinlock_t) in hard-IRQ context. This combination makes it impossible and leads to "sleeping while atomic" warnings.

Quoted 7 lines
Quoted 4 lines

Use one interrupt handler for both handlers (primary and secondary) and drop the IRQF_ONESHOT flag which is not needed.

Fixes e359b4411c283 ("serial: stm32: fix threaded interrupt handling")

I don't think a Fixes tag is warranted as this is only needed due to this undocumented quirk of PREEMPT_RT.

It is not an undocumented quirk of PREEMPT_RT. The part that might not be well documented is that IRQF_ONESHOT won't run the primary handler as a threaded handler. This is also the case for IRQF_NO_THREAD and IRQF_PERCPU but might be more obvious.
Anyway, if the primary handler is not threaded then it runs in HARDIRQ context and here you must not use a spinlock_t. This is documented in Documentation/locking/locktypes.rst and there is also a LOCKDEP warning for this on !RT which is off by default because it triggers with printk (and this is worked on).

Quoted 1 line

And this should not be backported in any case.

Such things have been backported via -stable in the past. If you disagree, please keep me in loop while is merged so I can poke people to backport it as part of the RT patch for the relevant kernels.

Quoted 1 line

Johan

Sebastian

#6 lore raw
Quoted 13 lines · Sebastian Andrzej Siewior
Quoted 12 lines · Johan Hovold
Quoted 10 lines · Marek Vasut

Requesting an interrupt with IRQF_ONESHOT will run the primary handler in the hard-IRQ context even in the force-threaded mode. The force-threaded mode is used by PREEMPT_RT in order to avoid acquiring sleeping locks (spinlock_t) in hard-IRQ context. This combination makes it impossible and leads to "sleeping while atomic" warnings.

Use one interrupt handler for both handlers (primary and secondary) and drop the IRQF_ONESHOT flag which is not needed.

Fixes e359b4411c283 ("serial: stm32: fix threaded interrupt handling")
Quoted 7 lines
Quoted 2 lines

I don't think a Fixes tag is warranted as this is only needed due to this undocumented quirk of PREEMPT_RT.

It is not an undocumented quirk of PREEMPT_RT. The part that might not be well documented is that IRQF_ONESHOT won't run the primary handler as a threaded handler. This is also the case for IRQF_NO_THREAD and IRQF_PERCPU but might be more obvious.

Yeah, that not being documented seems like an oversight as generally drivers should not need be changed to continue working on PREEMPT_RT (or with forced-threading generally).

Quoted 5 lines

Anyway, if the primary handler is not threaded then it runs in HARDIRQ context and here you must not use a spinlock_t. This is documented in Documentation/locking/locktypes.rst and there is also a LOCKDEP warning for this on !RT which is off by default because it triggers with printk (and this is worked on).

All interrupt handlers typically run in hard interrupt context unless explicitly requested to be threaded on !RT and drivers still use spinlock_t for that so not sure how that lockdep warning is supposed to work. Or do you mean that you have a lockdep warning specifically for IRQF_ONESHOT primary handlers?

Quoted 5 lines
Quoted 1 line

And this should not be backported in any case.

Such things have been backported via -stable in the past. If you disagree, please keep me in loop while is merged so I can poke people to backport it as part of the RT patch for the relevant kernels.

The author did not seem to think this was stable material as there is no cc-stable tag and it also seems fairly intrusive.

But if the ST guys or whoever cares about this driver are fine with this being backported, I don't really mind either.

Johan

#7 lore raw
Quoted 38 lines · Johan Hovold
Quoted 13 lines · Sebastian Andrzej Siewior
Quoted 12 lines · Johan Hovold
Quoted 10 lines · Marek Vasut

Requesting an interrupt with IRQF_ONESHOT will run the primary handler in the hard-IRQ context even in the force-threaded mode. The force-threaded mode is used by PREEMPT_RT in order to avoid acquiring sleeping locks (spinlock_t) in hard-IRQ context. This combination makes it impossible and leads to "sleeping while atomic" warnings.

Use one interrupt handler for both handlers (primary and secondary) and drop the IRQF_ONESHOT flag which is not needed.

Fixes e359b4411c283 ("serial: stm32: fix threaded interrupt handling")
Quoted 7 lines
Quoted 2 lines

I don't think a Fixes tag is warranted as this is only needed due to this undocumented quirk of PREEMPT_RT.

It is not an undocumented quirk of PREEMPT_RT. The part that might not be well documented is that IRQF_ONESHOT won't run the primary handler as a threaded handler. This is also the case for IRQF_NO_THREAD and IRQF_PERCPU but might be more obvious.

Yeah, that not being documented seems like an oversight as generally drivers should not need be changed to continue working on PREEMPT_RT (or with forced-threading generally).

Quoted 5 lines

Anyway, if the primary handler is not threaded then it runs in HARDIRQ context and here you must not use a spinlock_t. This is documented in Documentation/locking/locktypes.rst and there is also a LOCKDEP warning for this on !RT which is off by default because it triggers with printk (and this is worked on).

All interrupt handlers typically run in hard interrupt context unless explicitly requested to be threaded on !RT and drivers still use spinlock_t for that so not sure how that lockdep warning is supposed to work. Or do you mean that you have a lockdep warning specifically for IRQF_ONESHOT primary handlers?

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

And this should not be backported in any case.

Such things have been backported via -stable in the past. If you disagree, please keep me in loop while is merged so I can poke people to backport it as part of the RT patch for the relevant kernels.

The author did not seem to think this was stable material as there is no cc-stable tag and it also seems fairly intrusive.

The author does not have enough experience with preempt-rt to make that determination, hence deferred to Sebastian for better judgement.

Quoted 2 lines

But if the ST guys or whoever cares about this driver are fine with this being backported, I don't really mind either.

[...]

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#8 lore raw
Quoted 7 lines · Marek Vasut
Quoted 2 lines · Johan Hovold

The author did not seem to think this was stable material as there is no cc-stable tag and it also seems fairly intrusive.

The author does not have enough experience with preempt-rt to make that determination, hence deferred to Sebastian for better judgement.

Fair enough. And it's not obvious that the stable team should backport patches that only concern PREEMPT_RT either (e.g. as parts of it are still out-of-tree).

The stable tag is still missing from the final revision though.

Quoted 2 lines
Quoted 2 lines

But if the ST guys or whoever cares about this driver are fine with this being backported, I don't really mind either.

Johan

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#9 lore raw
Quoted 6 lines · Johan Hovold
Quoted 5 lines · Marek Vasut
Quoted 2 lines · Johan Hovold

The author did not seem to think this was stable material as there is no cc-stable tag and it also seems fairly intrusive.

Quoted 8 lines
Quoted 2 lines

The author does not have enough experience with preempt-rt to make that determination, hence deferred to Sebastian for better judgement.

Fair enough. And it's not obvious that the stable team should backport patches that only concern PREEMPT_RT either (e.g. as parts of it are still out-of-tree).

The stable tag is still missing from the final revision though.

Please pardon my ignorance, which stable tag is missing ?

Can you maybe just comment on the V4 and point this out to me ? I'll send a V5 then.

Thanks !

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#10 lore raw
Quoted 6 lines · Marek Vasut
Quoted 4 lines · Johan Hovold

Fair enough. And it's not obvious that the stable team should backport patches that only concern PREEMPT_RT either (e.g. as parts of it are still out-of-tree).

Quoted 6 lines
Quoted 1 line

The stable tag is still missing from the final revision though.

Please pardon my ignorance, which stable tag is missing ?

Can you maybe just comment on the V4 and point this out to me ? I'll send a V5 then.

It's gone from my inbox.

But as per Documentation/process/stable-kernel-rules.rst:

To have the patch automatically included in the stable tree, add the tag

.. code-block:: none

in the sign-off area. Once the patch is merged it will be applied to the stable tree without anything else needing to be done by the author or subsystem maintainer.

A Fixes tag only indicates which commit introduced a bug, not necessarily that the patch should be backported to stable (even if autosel is likely to pick it up these days).

Johan

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Tested-by on v3 1/1
#11 lore raw
In reply to Marek Vasut

Hi Marek,

It is OK for me.

Thanks,
Valentin

Quoted 94 lines · Marek Vasut

Requesting an interrupt with IRQF_ONESHOT will run the primary handler in the hard-IRQ context even in the force-threaded mode. The force-threaded mode is used by PREEMPT_RT in order to avoid acquiring sleeping locks (spinlock_t) in hard-IRQ context. This combination makes it impossible and leads to "sleeping while atomic" warnings.

Use one interrupt handler for both handlers (primary and secondary) and drop the IRQF_ONESHOT flag which is not needed.

Fixes e359b4411c283 ("serial: stm32: fix threaded interrupt handling")

---
Cc: Alexandre Torgue <[email protected]>
Cc: Erwan Le Ray <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Jiri Slaby <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Valentin Caron <[email protected]>
Cc: [email protected]
Cc: [email protected]
To: [email protected]
---
V2: - Update patch subject, was:
serial: stm32: Move hard IRQ handling to threaded interrupt context
- Use request_irq() instead, rename the IRQ handler function
V3: - Update the commit message per suggestion from Sebastian
- Add RB from Sebastian
- Add Fixes tag

---
  drivers/tty/serial/stm32-usart.c | 29 +++++++----------------------
  1 file changed, 7 insertions(+), 22 deletions(-)
drivers/tty/serial/stm32-usart.c +7 -22
index dfdbcf092facc..bbbab8dc2bfa9 100644
@@ -752,8 +752,9 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
  	struct tty_port *tport = &port->state->port;
  	struct stm32_port *stm32_port = to_stm32_port(port);
  	const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
-	u32 sr;
+	unsigned long flags;
  	unsigned int size;
+	u32 sr;
 
  	sr = readl_relaxed(port->membase + ofs->isr);
 
@@ -793,27 +794,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
  	}
 
  	if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
-		spin_lock(&port->lock);
+		spin_lock_irqsave(&port->lock, flags);
  		stm32_usart_transmit_chars(port);
-		spin_unlock(&port->lock);
+		spin_unlock_irqrestore(&port->lock, flags);
  	}
 
-	if (stm32_usart_rx_dma_enabled(port))
-		return IRQ_WAKE_THREAD;
-	else
-		return IRQ_HANDLED;
-}
-
-static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
-{
-	struct uart_port *port = ptr;
-	struct tty_port *tport = &port->state->port;
-	struct stm32_port *stm32_port = to_stm32_port(port);
-	unsigned int size;
-	unsigned long flags;
-
  	/* Receiver timeout irq for DMA RX */
-	if (!stm32_port->throttled) {
+	if (stm32_usart_rx_dma_enabled(port) && !stm32_port->throttled) {
  		spin_lock_irqsave(&port->lock, flags);
  		size = stm32_usart_receive_chars(port, false);
  		uart_unlock_and_check_sysrq_irqrestore(port, flags);
@@ -1016,10 +1003,8 @@ static int stm32_usart_startup(struct uart_port *port)
  	u32 val;
  	int ret;
 
-	ret = request_threaded_irq(port->irq, stm32_usart_interrupt,
-				   stm32_usart_threaded_interrupt,
-				   IRQF_ONESHOT | IRQF_NO_SUSPEND,
-				   name, port);
+	ret = request_irq(port->irq, stm32_usart_interrupt,
+			  IRQF_NO_SUSPEND, name, port);
  	if (ret)
  		return ret;