Problem with port driver - UART4.
by Rarebeast from LinuxQuestions.org on (#6GD6K)
UART4 serial port driver (w-apb-uart) - UART4 has only two lines - Rx and Tx.
Kernel 6.5.8 is used. Allwinner A40i processor.
DTS
In the DTS file it is redefined as UART:
&uart4 {
pinctrl-names = "default";
compatible = "snps,dw-apb-uart";
pinctrl-0 = <&uart4_ph_pins>;
rts-gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; //PH13
//rs485-rts-delay = <0 200>;
linux,rs485-enabled-at-boot-time;
status = "okay";
};
The GPIO PH13 port is used as an RTS pin (this is not hardware RTS).
In the device tree on the fourth port we enable the mode (linux,rs485-enabled-at-boot-time).
MY ACTIONS:
We open the port (using SCREEN) - reception occurs normally.
But as soon as we send the first line or character, the port hangs, immediately after the first send (it is successful, it arrives).
When sending, the port goes to the HIGH position, but after it does not return to the LOW position. The port stops working both for reception and transmission.
We used different speeds - 9600 to 115200, does not affect the behavior of the port.
When digging into the depths of the port driver (/linux-6.5.8/drivers/tty/serial/8250/8250_dw.c) and trying to debug, it turned out that if you paste the output into the console //dev_err() or dev_info() - everything starts work, but at the same time messages begin to arrive in the console from the ports.
The function static int dw8250_handle_irq(struct uart_port *p) calls:
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
bool skip_rx = false;
unsigned long flags;
u16 status;
if (iir & UART_IIR_NO_INT)
return 0;
//dev_err(port->dev, "Handle irq before breakpoint \n");//qq
spin_lock_irqsave(&port->lock, flags);
status = serial_lsr_in(up);
/*
* If port is stopped and there are no error conditions in the
* FIFO, then don't drain the FIFO, as this may lead to TTY buffer
* overflow. Not servicing, RX FIFO would trigger auto HW flow
* control when FIFO occupancy reaches preset threshold, thus
* halting RX. This only works when auto HW flow control is
* available.
*/
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
!(port->read_status_mask & UART_LSR_DR))
skip_rx = true;
if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0);
if (!up->dma handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
if (!up->dma up->dma->tx_err)
serial8250_tx_chars(up);
else if (!up->dma->tx_running)
__stop_tx(up);
}
uart_unlock_and_check_sysrq_irqrestore(port, flags);
return 1;
}
If the output of dev_err() is placed before spin_lock_irqsave(&port->lock, flags); then everything works. If after that it does not work, a spin_lock of the port occurs and in the future it is not released, a dead_lock occurs.
uart_unlock_and_check_sysrq_irqrestore(port, flags); - doesn't work.
QUESTION:
How to solve the problem so that the port works adequately, without sending messages from the ports to the console? Is the driver at fault?
TxRx Diagram - https://postimg.cc/BjVnxhD0
Kernel 6.5.8 is used. Allwinner A40i processor.
DTS
In the DTS file it is redefined as UART:
&uart4 {
pinctrl-names = "default";
compatible = "snps,dw-apb-uart";
pinctrl-0 = <&uart4_ph_pins>;
rts-gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; //PH13
//rs485-rts-delay = <0 200>;
linux,rs485-enabled-at-boot-time;
status = "okay";
};
The GPIO PH13 port is used as an RTS pin (this is not hardware RTS).
In the device tree on the fourth port we enable the mode (linux,rs485-enabled-at-boot-time).
MY ACTIONS:
We open the port (using SCREEN) - reception occurs normally.
But as soon as we send the first line or character, the port hangs, immediately after the first send (it is successful, it arrives).
When sending, the port goes to the HIGH position, but after it does not return to the LOW position. The port stops working both for reception and transmission.
We used different speeds - 9600 to 115200, does not affect the behavior of the port.
When digging into the depths of the port driver (/linux-6.5.8/drivers/tty/serial/8250/8250_dw.c) and trying to debug, it turned out that if you paste the output into the console //dev_err() or dev_info() - everything starts work, but at the same time messages begin to arrive in the console from the ports.
The function static int dw8250_handle_irq(struct uart_port *p) calls:
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
bool skip_rx = false;
unsigned long flags;
u16 status;
if (iir & UART_IIR_NO_INT)
return 0;
//dev_err(port->dev, "Handle irq before breakpoint \n");//qq
spin_lock_irqsave(&port->lock, flags);
status = serial_lsr_in(up);
/*
* If port is stopped and there are no error conditions in the
* FIFO, then don't drain the FIFO, as this may lead to TTY buffer
* overflow. Not servicing, RX FIFO would trigger auto HW flow
* control when FIFO occupancy reaches preset threshold, thus
* halting RX. This only works when auto HW flow control is
* available.
*/
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
!(port->read_status_mask & UART_LSR_DR))
skip_rx = true;
if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0);
if (!up->dma handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
if (!up->dma up->dma->tx_err)
serial8250_tx_chars(up);
else if (!up->dma->tx_running)
__stop_tx(up);
}
uart_unlock_and_check_sysrq_irqrestore(port, flags);
return 1;
}
If the output of dev_err() is placed before spin_lock_irqsave(&port->lock, flags); then everything works. If after that it does not work, a spin_lock of the port occurs and in the future it is not released, a dead_lock occurs.
uart_unlock_and_check_sysrq_irqrestore(port, flags); - doesn't work.
QUESTION:
How to solve the problem so that the port works adequately, without sending messages from the ports to the console? Is the driver at fault?
TxRx Diagram - https://postimg.cc/BjVnxhD0