mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00

The following splat has been observed on a SAMA5D27 platform using atmel_serial: BUG: sleeping function called from invalid context at kernel/irq/manage.c:738 in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 27, name: kworker/u5:0 preempt_count: 1, expected: 0 INFO: lockdep is turned off. irq event stamp: 0 hardirqs last enabled at (0): [<00000000>] 0x0 hardirqs last disabled at (0): [<c01588f0>] copy_process+0x1c4c/0x7bec softirqs last enabled at (0): [<c0158944>] copy_process+0x1ca0/0x7bec softirqs last disabled at (0): [<00000000>] 0x0 CPU: 0 UID: 0 PID: 27 Comm: kworker/u5:0 Not tainted 6.13.0-rc7+ #74 Hardware name: Atmel SAMA5 Workqueue: hci0 hci_power_on [bluetooth] Call trace: unwind_backtrace from show_stack+0x18/0x1c show_stack from dump_stack_lvl+0x44/0x70 dump_stack_lvl from __might_resched+0x38c/0x598 __might_resched from disable_irq+0x1c/0x48 disable_irq from mctrl_gpio_disable_ms+0x74/0xc0 mctrl_gpio_disable_ms from atmel_disable_ms.part.0+0x80/0x1f4 atmel_disable_ms.part.0 from atmel_set_termios+0x764/0x11e8 atmel_set_termios from uart_change_line_settings+0x15c/0x994 uart_change_line_settings from uart_set_termios+0x2b0/0x668 uart_set_termios from tty_set_termios+0x600/0x8ec tty_set_termios from ttyport_set_flow_control+0x188/0x1e0 ttyport_set_flow_control from wilc_setup+0xd0/0x524 [hci_wilc] wilc_setup [hci_wilc] from hci_dev_open_sync+0x330/0x203c [bluetooth] hci_dev_open_sync [bluetooth] from hci_dev_do_open+0x40/0xb0 [bluetooth] hci_dev_do_open [bluetooth] from hci_power_on+0x12c/0x664 [bluetooth] hci_power_on [bluetooth] from process_one_work+0x998/0x1a38 process_one_work from worker_thread+0x6e0/0xfb4 worker_thread from kthread+0x3d4/0x484 kthread from ret_from_fork+0x14/0x28 This warning is emitted when trying to toggle, at the highest level, some flow control (with serdev_device_set_flow_control) in a device driver. At the lowest level, the atmel_serial driver is using serial_mctrl_gpio lib to enable/disable the corresponding IRQs accordingly. The warning emitted by CONFIG_DEBUG_ATOMIC_SLEEP is due to disable_irq (called in mctrl_gpio_disable_ms) being possibly called in some atomic context (some tty drivers perform modem lines configuration in regions protected by port lock). Split mctrl_gpio_disable_ms into two differents APIs, a non-blocking one and a blocking one. Replace mctrl_gpio_disable_ms calls with the relevant version depending on whether the call is protected by some port lock. Suggested-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Alexis Lothoré <alexis.lothore@bootlin.com> Acked-by: Richard Genoud <richard.genoud@bootlin.com> Link: https://lore.kernel.org/r/20250217-atomic_sleep_mctrl_serial_gpio-v3-1-59324b313eef@bootlin.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
107 lines
3.4 KiB
ReStructuredText
107 lines
3.4 KiB
ReStructuredText
====================
|
|
Low Level Serial API
|
|
====================
|
|
|
|
|
|
This document is meant as a brief overview of some aspects of the new serial
|
|
driver. It is not complete, any questions you have should be directed to
|
|
<rmk@arm.linux.org.uk>
|
|
|
|
The reference implementation is contained within amba-pl011.c.
|
|
|
|
|
|
|
|
Low Level Serial Hardware Driver
|
|
--------------------------------
|
|
|
|
The low level serial hardware driver is responsible for supplying port
|
|
information (defined by uart_port) and a set of control methods (defined
|
|
by uart_ops) to the core serial driver. The low level driver is also
|
|
responsible for handling interrupts for the port, and providing any
|
|
console support.
|
|
|
|
|
|
Console Support
|
|
---------------
|
|
|
|
The serial core provides a few helper functions. This includes identifying
|
|
the correct port structure (via uart_get_console()) and decoding command line
|
|
arguments (uart_parse_options()).
|
|
|
|
There is also a helper function (uart_console_write()) which performs a
|
|
character by character write, translating newlines to CRLF sequences.
|
|
Driver writers are recommended to use this function rather than implementing
|
|
their own version.
|
|
|
|
|
|
Locking
|
|
-------
|
|
|
|
It is the responsibility of the low level hardware driver to perform the
|
|
necessary locking using port->lock. There are some exceptions (which
|
|
are described in the struct uart_ops listing below.)
|
|
|
|
There are two locks. A per-port spinlock, and an overall semaphore.
|
|
|
|
From the core driver perspective, the port->lock locks the following
|
|
data::
|
|
|
|
port->mctrl
|
|
port->icount
|
|
port->state->xmit.head (circ_buf->head)
|
|
port->state->xmit.tail (circ_buf->tail)
|
|
|
|
The low level driver is free to use this lock to provide any additional
|
|
locking.
|
|
|
|
The port_sem semaphore is used to protect against ports being added/
|
|
removed or reconfigured at inappropriate times. Since v2.6.27, this
|
|
semaphore has been the 'mutex' member of the tty_port struct, and
|
|
commonly referred to as the port mutex.
|
|
|
|
|
|
uart_ops
|
|
--------
|
|
|
|
.. kernel-doc:: include/linux/serial_core.h
|
|
:identifiers: uart_ops
|
|
|
|
Other functions
|
|
---------------
|
|
|
|
.. kernel-doc:: drivers/tty/serial/serial_core.c
|
|
:identifiers: uart_update_timeout uart_get_baud_rate uart_get_divisor
|
|
uart_match_port uart_write_wakeup uart_register_driver
|
|
uart_unregister_driver uart_suspend_port uart_resume_port
|
|
uart_add_one_port uart_remove_one_port uart_console_write
|
|
uart_parse_earlycon uart_parse_options uart_set_options
|
|
uart_get_lsr_info uart_handle_dcd_change uart_handle_cts_change
|
|
uart_try_toggle_sysrq uart_get_console
|
|
|
|
.. kernel-doc:: include/linux/serial_core.h
|
|
:identifiers: uart_port_tx_limited uart_port_tx
|
|
|
|
Other notes
|
|
-----------
|
|
|
|
It is intended some day to drop the 'unused' entries from uart_port, and
|
|
allow low level drivers to register their own individual uart_port's with
|
|
the core. This will allow drivers to use uart_port as a pointer to a
|
|
structure containing both the uart_port entry with their own extensions,
|
|
thus::
|
|
|
|
struct my_port {
|
|
struct uart_port port;
|
|
int my_stuff;
|
|
};
|
|
|
|
Modem control lines via GPIO
|
|
----------------------------
|
|
|
|
Some helpers are provided in order to set/get modem control lines via GPIO.
|
|
|
|
.. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c
|
|
:identifiers: mctrl_gpio_init mctrl_gpio_to_gpiod
|
|
mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms
|
|
mctrl_gpio_disable_ms_sync mctrl_gpio_disable_ms_no_sync
|