summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0012-serial-core-Implement-processing-in-port-lock-wrappe.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0012-serial-core-Implement-processing-in-port-lock-wrappe.patch')
-rw-r--r--debian/patches-rt/0012-serial-core-Implement-processing-in-port-lock-wrappe.patch180
1 files changed, 180 insertions, 0 deletions
diff --git a/debian/patches-rt/0012-serial-core-Implement-processing-in-port-lock-wrappe.patch b/debian/patches-rt/0012-serial-core-Implement-processing-in-port-lock-wrappe.patch
new file mode 100644
index 0000000000..1d136131f8
--- /dev/null
+++ b/debian/patches-rt/0012-serial-core-Implement-processing-in-port-lock-wrappe.patch
@@ -0,0 +1,180 @@
+From: John Ogness <john.ogness@linutronix.de>
+Date: Wed, 17 Apr 2024 14:41:16 +0000
+Subject: [PATCH 12/46] serial: core: Implement processing in port->lock
+ wrapper
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.9/older/patches-6.9-rt5.tar.xz
+
+Currently the port->lock wrappers uart_port_lock(),
+uart_port_unlock() (and their variants) only lock/unlock
+the spin_lock.
+
+If the port is an nbcon console, the wrappers must also
+acquire/release the console and mark the region as unsafe. This
+allows general port->lock synchronization to be synchronized
+with the nbcon console ownership.
+
+Note that __uart_port_using_nbcon() relies on the port->lock
+being held while a console is added and removed from the
+console list (i.e. all uart nbcon drivers *must* take the
+port->lock in their device_lock() callbacks).
+
+Signed-off-by: John Ogness <john.ogness@linutronix.de>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ include/linux/serial_core.h | 82 ++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 80 insertions(+), 2 deletions(-)
+
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -12,6 +12,8 @@
+ #include <linux/console.h>
+ #include <linux/interrupt.h>
+ #include <linux/circ_buf.h>
++#include <linux/lockdep.h>
++#include <linux/printk.h>
+ #include <linux/spinlock.h>
+ #include <linux/sched.h>
+ #include <linux/tty.h>
+@@ -626,6 +628,60 @@ static inline void uart_port_set_cons(st
+ up->cons = con;
+ __uart_port_unlock_irqrestore(up, flags);
+ }
++
++/* Only for internal port lock wrapper usage. */
++static inline bool __uart_port_using_nbcon(struct uart_port *up)
++{
++ lockdep_assert_held_once(&up->lock);
++
++ if (likely(!uart_console(up)))
++ return false;
++
++ /*
++ * @up->cons is only modified under the port lock. Therefore it is
++ * certain that it cannot disappear here.
++ *
++ * @up->cons->node is added/removed from the console list under the
++ * port lock. Therefore it is certain that the registration status
++ * cannot change here, thus @up->cons->flags can be read directly.
++ */
++ if (hlist_unhashed_lockless(&up->cons->node) ||
++ !(up->cons->flags & CON_NBCON) ||
++ !up->cons->write_atomic) {
++ return false;
++ }
++
++ return true;
++}
++
++/* Only for internal port lock wrapper usage. */
++static inline bool __uart_port_nbcon_try_acquire(struct uart_port *up)
++{
++ if (!__uart_port_using_nbcon(up))
++ return true;
++
++ return nbcon_driver_try_acquire(up->cons);
++}
++
++/* Only for internal port lock wrapper usage. */
++static inline void __uart_port_nbcon_acquire(struct uart_port *up)
++{
++ if (!__uart_port_using_nbcon(up))
++ return;
++
++ while (!nbcon_driver_try_acquire(up->cons))
++ cpu_relax();
++}
++
++/* Only for internal port lock wrapper usage. */
++static inline void __uart_port_nbcon_release(struct uart_port *up)
++{
++ if (!__uart_port_using_nbcon(up))
++ return;
++
++ nbcon_driver_release(up->cons);
++}
++
+ /**
+ * uart_port_lock - Lock the UART port
+ * @up: Pointer to UART port structure
+@@ -633,6 +689,7 @@ static inline void uart_port_set_cons(st
+ static inline void uart_port_lock(struct uart_port *up)
+ {
+ spin_lock(&up->lock);
++ __uart_port_nbcon_acquire(up);
+ }
+
+ /**
+@@ -642,6 +699,7 @@ static inline void uart_port_lock(struct
+ static inline void uart_port_lock_irq(struct uart_port *up)
+ {
+ spin_lock_irq(&up->lock);
++ __uart_port_nbcon_acquire(up);
+ }
+
+ /**
+@@ -652,6 +710,7 @@ static inline void uart_port_lock_irq(st
+ static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
+ {
+ spin_lock_irqsave(&up->lock, *flags);
++ __uart_port_nbcon_acquire(up);
+ }
+
+ /**
+@@ -662,7 +721,15 @@ static inline void uart_port_lock_irqsav
+ */
+ static inline bool uart_port_trylock(struct uart_port *up)
+ {
+- return spin_trylock(&up->lock);
++ if (!spin_trylock(&up->lock))
++ return false;
++
++ if (!__uart_port_nbcon_try_acquire(up)) {
++ spin_unlock(&up->lock);
++ return false;
++ }
++
++ return true;
+ }
+
+ /**
+@@ -674,7 +741,15 @@ static inline bool uart_port_trylock(str
+ */
+ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags)
+ {
+- return spin_trylock_irqsave(&up->lock, *flags);
++ if (!spin_trylock_irqsave(&up->lock, *flags))
++ return false;
++
++ if (!__uart_port_nbcon_try_acquire(up)) {
++ spin_unlock_irqrestore(&up->lock, *flags);
++ return false;
++ }
++
++ return true;
+ }
+
+ /**
+@@ -683,6 +758,7 @@ static inline bool uart_port_trylock_irq
+ */
+ static inline void uart_port_unlock(struct uart_port *up)
+ {
++ __uart_port_nbcon_release(up);
+ spin_unlock(&up->lock);
+ }
+
+@@ -692,6 +768,7 @@ static inline void uart_port_unlock(stru
+ */
+ static inline void uart_port_unlock_irq(struct uart_port *up)
+ {
++ __uart_port_nbcon_release(up);
+ spin_unlock_irq(&up->lock);
+ }
+
+@@ -702,6 +779,7 @@ static inline void uart_port_unlock_irq(
+ */
+ static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
+ {
++ __uart_port_nbcon_release(up);
+ spin_unlock_irqrestore(&up->lock, flags);
+ }
+