Message ID | 20230914183831.587273-2-john.ogness@linutronix.de |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:172:b0:3f2:4152:657d with SMTP id h50csp3003744vqi; Mon, 18 Sep 2023 15:57:15 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGP1lGJKa1Tvv7kgg05aXFautUAvqsdWylQnkU4rvfnU4HaE+7lAa4L94Uu9zPRHqZ5ewTz X-Received: by 2002:a17:90b:3103:b0:25d:eca9:1621 with SMTP id gc3-20020a17090b310300b0025deca91621mr7902608pjb.6.1695077835740; Mon, 18 Sep 2023 15:57:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695077835; cv=none; d=google.com; s=arc-20160816; b=NdgGRySCgHwKV2H6egiKQ5oQhy/jT8gTR0G73kDnZX1ECuXsmR+JF/mgNx0bp9o2cc Rr3gOkVEyLDYtQM12gi/c9Pk0jf7ToLfJX8XgLodMrrG0TJkaCmYGHKBNteNWnV3WeT4 cHW6as9eFY9g4U21/CDgxjq73VWc9iRg/lS6CScOtQxpogMfVfnKUtEgf3pzsRc9LRQv fluWS3qoEuKSGSGaacY5jnkjFHxaJ461PFQlG5noGg29xzH4Ny/BF/aVlx0miLyEdNVA FKiE75KbzzpGepEYb7B4WWBboxRqU9lI9O4TEoZzrf30+UYENexjBX3JTpzNLA7Dtfdg sKkA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:dkim-signature :dkim-signature:from; bh=IRoapPsp3k8C9+cAJncEIUfgF6L1OgYHKNIWMNQArN8=; fh=qmZFnekuDs4T9icLmieAH3NNHXuS0/kWBnXi7iQsZPY=; b=mzN7G21TSMc/nDBkXvPYvGdxcol1oeWpijH9fukDbDhDeI+bEBpgC80zI2DyqGTKkd gYByb3tXXI5NpVZ9pmIHPjyoAn/JUDKlacjNVZnNJCZ7sADwaXoNtVPBOJuURSceoCLL ACx5Qd//LQu2cFjxcTu4/J1VgxCGByneuazJL+0TJkZAK67m7kISfspznocWOfPCuKRA XvKWJRPhtLAXKaCNLF7zA63nEu/QcN2XLD21aMFJwnsIwuRHu7wkO9BQR2Boc6qEB3k5 BguwRrxMJoDDdZ1Q5dpqoB5RravCTila+4fHbkCiRDqWHGzPHX2YY0ZCGTPwyVuOOr3A zbvQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=VAjKIhOb; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.36 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from pete.vger.email (pete.vger.email. [23.128.96.36]) by mx.google.com with ESMTPS id c1-20020a17090ad90100b0026b49c1aa50si6870463pjv.111.2023.09.18.15.57.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Sep 2023 15:57:15 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.36 as permitted sender) client-ip=23.128.96.36; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=VAjKIhOb; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.36 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by pete.vger.email (Postfix) with ESMTP id 0289A81F346F; Thu, 14 Sep 2023 11:39:50 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at pete.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241479AbjINSit (ORCPT <rfc822;pwkd43@gmail.com> + 33 others); Thu, 14 Sep 2023 14:38:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234957AbjINSiq (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Thu, 14 Sep 2023 14:38:46 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E0A781FF9; Thu, 14 Sep 2023 11:38:41 -0700 (PDT) From: John Ogness <john.ogness@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694716719; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IRoapPsp3k8C9+cAJncEIUfgF6L1OgYHKNIWMNQArN8=; b=VAjKIhObU4Ecwzj1Ft23hUIFCg5wNU+ACZXfHOo/+M6G3rDdjIutIP/3dgKZphFycD7k0s l1K/shKjUF1xNDyqSV4Dkv1WCexNBS4t69JIncUEixls1YhZ/pLnSCgDpEory16tlJ3aaK cTsL9IOd8JYrt8dYej3n1jevYWZHoDYTaJtVMpwp/BHiRAyRsFxkoewey2tW8f/zXlHHoj eGxIhZNWggKOIC77flgOvFXuitF29LOz6qsVQG5nx2unbIXnsGYvp0nQHU7vFHpswVtoGd qFrRpKlOyVTIQm/uj3/xhPNHlPXIYSjTqnj+ukPYGxr4V79XY9RgkxxGqm6CVQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694716719; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IRoapPsp3k8C9+cAJncEIUfgF6L1OgYHKNIWMNQArN8=; b=wGLW0CPqtjKXdq32BWOBlskt8IKEQHA9vLWBa4IeEQiBvGjl9GrE1AxJD/0KbuJjMJhKKB l4R6nV8mtg7pUYBQ== To: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org>, linux-serial@vger.kernel.org, Petr Mladek <pmladek@suse.com>, Thomas Gleixner <tglx@linutronix.de>, linux-kernel@vger.kernel.org Subject: [PATCH tty v1 01/74] serial: core: Provide port lock wrappers Date: Thu, 14 Sep 2023 20:43:18 +0206 Message-Id: <20230914183831.587273-2-john.ogness@linutronix.de> In-Reply-To: <20230914183831.587273-1-john.ogness@linutronix.de> References: <20230914183831.587273-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (pete.vger.email [0.0.0.0]); Thu, 14 Sep 2023 11:39:50 -0700 (PDT) X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INVALID_DATE_TZ_ABSURD, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on pete.vger.email X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1777118132341386388 X-GMAIL-MSGID: 1777417936397404404 |
Series |
serial: wrappers for uart port lock
|
|
Commit Message
John Ogness
Sept. 14, 2023, 6:37 p.m. UTC
From: Thomas Gleixner <tglx@linutronix.de> When a serial port is used for kernel console output, then all modifications to the UART registers which are done from other contexts, e.g. getty, termios, are interference points for the kernel console. So far this has been ignored and the printk output is based on the principle of hope. The rework of the console infrastructure which aims to support threaded and atomic consoles, requires to mark sections which modify the UART registers as unsafe. This allows the atomic write function to make informed decisions and eventually to restore operational state. It also allows to prevent the regular UART code from modifying UART registers while printk output is in progress. All modifications of UART registers are guarded by the UART port lock, which provides an obvious synchronization point with the console infrastructure. Provide wrapper functions for spin_[un]lock*(port->lock) invocations so that the console mechanics can be applied later on at a single place and does not require to copy the same logic all over the drivers. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- include/linux/serial_core.h | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
Comments
On Thu 2023-09-14 20:43:18, John Ogness wrote: > From: Thomas Gleixner <tglx@linutronix.de> > > When a serial port is used for kernel console output, then all > modifications to the UART registers which are done from other contexts, > e.g. getty, termios, are interference points for the kernel console. > > So far this has been ignored and the printk output is based on the > principle of hope. The rework of the console infrastructure which aims to > support threaded and atomic consoles, requires to mark sections which > modify the UART registers as unsafe. This allows the atomic write function > to make informed decisions and eventually to restore operational state. It > also allows to prevent the regular UART code from modifying UART registers > while printk output is in progress. > > All modifications of UART registers are guarded by the UART port lock, > which provides an obvious synchronization point with the console > infrastructure. > > Provide wrapper functions for spin_[un]lock*(port->lock) invocations so > that the console mechanics can be applied later on at a single place and > does not require to copy the same logic all over the drivers. > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > --- > include/linux/serial_core.h | 79 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 79 insertions(+) > > diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h > index bb6f073bc159..f1d5c0d1568c 100644 > --- a/include/linux/serial_core.h > +++ b/include/linux/serial_core.h > +/** > + * uart_port_lock_irqsave - Lock the UART port, save and disable interrupts > + * @up: Pointer to UART port structure > + * @flags: Pointer to interrupt flags storage > + */ > +static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags) > +{ > + spin_lock_irqsave(&up->lock, *flags); > +} IMHO, it would have been better to pass the flags variable directly via a macro as it is done in most *_lock_*_irqsafe() APIs. I mean something like: /** * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts * @up: Pointer to UART port structure * @flags: Interrupt flags storage * * Returns: True if lock was acquired, false otherwise */ #define uart_port_lock_irqsave(up, flags) \ ({ \ local_irq_save(flags); \ uart_port_lock(lock) \ }) > + > +/** > + * uart_port_trylock - Try to lock the UART port > + * @up: Pointer to UART port structure > + * > + * Returns: True if lock was acquired, false otherwise > + */ > +static inline bool uart_port_trylock(struct uart_port *up) > +{ > + return spin_trylock(&up->lock); > +} > + > +/** > + * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts > + * @up: Pointer to UART port structure > + * @flags: Pointer to interrupt flags storage > + * > + * Returns: True if lock was acquired, false otherwise > + */ > +static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags) > +{ > + return spin_trylock_irqsave(&up->lock, *flags); > +} Similar here: /** * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts * @up: Pointer to UART port structure * @flags: Interrupt flags storage * * Returns: True if lock was acquired, false otherwise */ #define uart_port_trylock_irqsave(up, flags) \ ({ \ bool __ret; \ \ local_irq_save(flags); \ __ret = uart_port_trylock(lock) \ if (!__ret) \ local_irq_restore(flags); \ __ret; \ }) I do not resist on this rather cosmetic change. The current code seems to be doing what is expected. Feel free to keep it and use: Reviewed-by: Petr Mladek <pmladek@suse.com> Best Regards, Petr PS: I am sorry for the late review. I have made a quick look on Monday and it looked straightforward. I have got this idea today when having a closer look.
On Tue, Sep 19, 2023 at 04:24:48PM +0200, Petr Mladek wrote: > On Thu 2023-09-14 20:43:18, John Ogness wrote: > > From: Thomas Gleixner <tglx@linutronix.de> > > > > When a serial port is used for kernel console output, then all > > modifications to the UART registers which are done from other contexts, > > e.g. getty, termios, are interference points for the kernel console. > > > > So far this has been ignored and the printk output is based on the > > principle of hope. The rework of the console infrastructure which aims to > > support threaded and atomic consoles, requires to mark sections which > > modify the UART registers as unsafe. This allows the atomic write function > > to make informed decisions and eventually to restore operational state. It > > also allows to prevent the regular UART code from modifying UART registers > > while printk output is in progress. > > > > All modifications of UART registers are guarded by the UART port lock, > > which provides an obvious synchronization point with the console > > infrastructure. > > > > Provide wrapper functions for spin_[un]lock*(port->lock) invocations so > > that the console mechanics can be applied later on at a single place and > > does not require to copy the same logic all over the drivers. > > > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > > --- > > include/linux/serial_core.h | 79 +++++++++++++++++++++++++++++++++++++ > > 1 file changed, 79 insertions(+) > > > > diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h > > index bb6f073bc159..f1d5c0d1568c 100644 > > --- a/include/linux/serial_core.h > > +++ b/include/linux/serial_core.h > > +/** > > + * uart_port_lock_irqsave - Lock the UART port, save and disable interrupts > > + * @up: Pointer to UART port structure > > + * @flags: Pointer to interrupt flags storage > > + */ > > +static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags) > > +{ > > + spin_lock_irqsave(&up->lock, *flags); > > +} > > IMHO, it would have been better to pass the flags variable directly > via a macro as it is done in most *_lock_*_irqsafe() APIs. I mean > something like: > > /** > * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts > * @up: Pointer to UART port structure > * @flags: Interrupt flags storage > * > * Returns: True if lock was acquired, false otherwise > */ > #define uart_port_lock_irqsave(up, flags) \ > ({ \ > local_irq_save(flags); \ > uart_port_lock(lock) \ > }) > > > + > > +/** > > + * uart_port_trylock - Try to lock the UART port > > + * @up: Pointer to UART port structure > > + * > > + * Returns: True if lock was acquired, false otherwise > > + */ > > +static inline bool uart_port_trylock(struct uart_port *up) > > +{ > > + return spin_trylock(&up->lock); > > +} > > + > > +/** > > + * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts > > + * @up: Pointer to UART port structure > > + * @flags: Pointer to interrupt flags storage > > + * > > + * Returns: True if lock was acquired, false otherwise > > + */ > > +static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags) > > +{ > > + return spin_trylock_irqsave(&up->lock, *flags); > > +} > > Similar here: > > /** > * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts > * @up: Pointer to UART port structure > * @flags: Interrupt flags storage > * > * Returns: True if lock was acquired, false otherwise > */ > #define uart_port_trylock_irqsave(up, flags) \ > ({ \ > bool __ret; \ > \ > local_irq_save(flags); \ > __ret = uart_port_trylock(lock) \ > if (!__ret) \ > local_irq_restore(flags); \ > __ret; \ > }) What is the difference here of a macro vs. an inline function going to do for the resulting binary? The important thing is now we have wrapper functions, people can tweak them all they want to see if we can get better results :) thanks for the review! greg k-h
On Tue, Sep 19 2023 at 16:24, Petr Mladek wrote: > On Thu 2023-09-14 20:43:18, John Ogness wrote: > IMHO, it would have been better to pass the flags variable directly > via a macro as it is done in most *_lock_*_irqsafe() APIs. I mean > something like: > > /** > * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts > * @up: Pointer to UART port structure > * @flags: Interrupt flags storage > * > * Returns: True if lock was acquired, false otherwise > */ > #define uart_port_lock_irqsave(up, flags) \ > ({ \ > local_irq_save(flags); \ > uart_port_lock(lock) \ > }) It's worse. 1) Macros are not type safe by themself and rely on type safety of the inner workings. 2) Macros are bad for grep as you can't search for a 'struct foo *' argument. Even semantic parsers have their problems with macro constructs. I just learned that again when doing this. 3) Macros are just horrible to read 4) If you want to out of line the wrapper later, then you still have to keep the macro around because the 'flags' argument is by value and not a pointer. From a code generation point of view it's completely irrelevant whether you have a macro or an inline. That was different 25 years ago, but who cares about museum compilers today. Thanks, tglx
Adding Peter into Cc who also has a big experience with locking APIs. Well, I think that he would not care ;-) On Tue 2023-09-19 21:51:12, Thomas Gleixner wrote: > On Tue, Sep 19 2023 at 16:24, Petr Mladek wrote: > > On Thu 2023-09-14 20:43:18, John Ogness wrote: > > IMHO, it would have been better to pass the flags variable directly > > via a macro as it is done in most *_lock_*_irqsafe() APIs. I mean > > something like: > > > > /** > > * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts > > * @up: Pointer to UART port structure > > * @flags: Interrupt flags storage > > * > > * Returns: True if lock was acquired, false otherwise > > */ > > #define uart_port_lock_irqsave(up, flags) \ > > ({ \ > > local_irq_save(flags); \ > > uart_port_lock(lock) \ > > }) > > It's worse. > > 1) Macros are not type safe by themself and rely on type safety > of the inner workings. > > 2) Macros are bad for grep as you can't search for a 'struct foo *' > argument. Even semantic parsers have their problems with macro > constructs. I just learned that again when doing this. > > 3) Macros are just horrible to read > > 4) If you want to out of line the wrapper later, then you still > have to keep the macro around because the 'flags' argument is by > value and not a pointer. > > >From a code generation point of view it's completely irrelevant whether > you have a macro or an inline. That was different 25 years ago, but who > cares about museum compilers today. I probably was not clear enough. The difference and the motivation is to pass the "flags" variable instead of pointer "*flags". Both most common APIs, local_irq_save(flags) and spin_lock_irqsave(lock, flags) pass the variable. Also most subsystem specific wrappers do so. IMHO, some consistency makes the life easier for developers, especially for frequently used API. And the patchset seems to be adding >350 users of the uart_port_lock_*irqsave() API. I do not know. Maybe using macros was bad decision for local_irq*() and spin_lock*() API. Anyway, we are going to live with the uart_port_lock*() API for a looong time. And I want to be sure that we do not create (small) headaches for future generations. OK, maybe this particular difference is not important enough. As I said, I do not resist on the change. Best Regards, Petr
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index bb6f073bc159..f1d5c0d1568c 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -588,6 +588,85 @@ struct uart_port { void *private_data; /* generic platform data pointer */ }; +/** + * uart_port_lock - Lock the UART port + * @up: Pointer to UART port structure + */ +static inline void uart_port_lock(struct uart_port *up) +{ + spin_lock(&up->lock); +} + +/** + * uart_port_lock_irq - Lock the UART port and disable interrupts + * @up: Pointer to UART port structure + */ +static inline void uart_port_lock_irq(struct uart_port *up) +{ + spin_lock_irq(&up->lock); +} + +/** + * uart_port_lock_irqsave - Lock the UART port, save and disable interrupts + * @up: Pointer to UART port structure + * @flags: Pointer to interrupt flags storage + */ +static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags) +{ + spin_lock_irqsave(&up->lock, *flags); +} + +/** + * uart_port_trylock - Try to lock the UART port + * @up: Pointer to UART port structure + * + * Returns: True if lock was acquired, false otherwise + */ +static inline bool uart_port_trylock(struct uart_port *up) +{ + return spin_trylock(&up->lock); +} + +/** + * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts + * @up: Pointer to UART port structure + * @flags: Pointer to interrupt flags storage + * + * Returns: True if lock was acquired, false otherwise + */ +static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags) +{ + return spin_trylock_irqsave(&up->lock, *flags); +} + +/** + * uart_port_unlock - Unlock the UART port + * @up: Pointer to UART port structure + */ +static inline void uart_port_unlock(struct uart_port *up) +{ + spin_unlock(&up->lock); +} + +/** + * uart_port_unlock_irq - Unlock the UART port and re-enable interrupts + * @up: Pointer to UART port structure + */ +static inline void uart_port_unlock_irq(struct uart_port *up) +{ + spin_unlock_irq(&up->lock); +} + +/** + * uart_port_lock_irqrestore - Unlock the UART port, restore interrupts + * @up: Pointer to UART port structure + * @flags: The saved interrupt flags for restore + */ +static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags) +{ + spin_unlock_irqrestore(&up->lock, flags); +} + static inline int serial_port_in(struct uart_port *up, int offset) { return up->serial_in(up, offset);