diff options
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.patch | 180 |
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); + } + |