Skip to contentSkip to conversation

Handling of automatic flow control in UART drivers

DISCUSSION Johannes Thumshirn 3 participants 6 messages Oct 13, 2014 – Oct 23, 2014 TTY layer and serial drivers

lore
Share & tools
lore
#0 lore raw

Hi,

We have problem with automatic flow control (i.e. auto RTS/CTS handshaking) in our uart driver (men_z135_uart.c). It's probably less a technical but a problem with me understanding the API.

I active the hardware auto flow control feature on the CRTSCTS flag in my uart_ops->set_termios() function. But then the RTS flag is set on every call of the uart_ops->set_mctrl() function, this seems to confuse the hardware. Is there a way to tell the tty layer that flow control is handled solely by hardware? I.e. is there a way of telling serial core to leave out the calls to uart_set_mctrl()/uart_clear_mctrl() in uart_throttle()/uart_unthrottle(), or is setting UPF_FLOW_HARD and then implementing a dummy port->ops->{un}throttle() the correct way?

Are there any drivers that use a hardware's automatic flow control feature I can use as an example? A fast grep on AFE reveals some spots, but I can't really find a difference to my implementation.

Thanks in advance,
Johannes

#1 lore raw
Quoted 4 lines · Johannes Thumshirn

I active the hardware auto flow control feature on the CRTSCTS flag in my uart_ops->set_termios() function. But then the RTS flag is set on every call of the uart_ops->set_mctrl() function, this seems to confuse the hardware.

Perhaps in that situation you should ignore the RTS setting in set_mctrl() if CRTSCTS is enabled.

Signature · 3 lines
Grant Edwards               grant.b.edwards        Yow! Zippy's brain cells
                                  at               are straining to bridge
                              gmail.com            synapses ...
#2 lore raw
In reply to Johannes Thumshirn
Quoted 15 lines · Johannes Thumshirn

Hi,

We have problem with automatic flow control (i.e. auto RTS/CTS handshaking) in our uart driver (men_z135_uart.c). It's probably less a technical but a problem with me understanding the API.

I active the hardware auto flow control feature on the CRTSCTS flag in my uart_ops->set_termios() function. But then the RTS flag is set on every call of the uart_ops->set_mctrl() function, this seems to confuse the hardware. Is there a way to tell the tty layer that flow control is handled solely by hardware? I.e. is there a way of telling serial core to leave out the calls to uart_set_mctrl()/uart_clear_mctrl() in uart_throttle()/uart_unthrottle(), or is setting UPF_FLOW_HARD and then implementing a dummy port->ops->{un}throttle() the correct way?

Quoted 3 lines

Are there any drivers that use a hardware's automatic flow control feature I can use as an example? A fast grep on AFE reveals some spots, but I can't really find a difference to my implementation.

uart_throttle()/uart_unthrottle() is essentially broken.

If the RTS pin is driveable, then the UART driver must respond to TIOCM_RTS set and clear in the ->set_mctrl() handler, regardless of any mode selected in termios or other mode such as autoRTS.

This requirement exists because both userspace and other kernel drivers may want to drive RTS for their own purposes.

For example, a bluetooth UART HCI may allow the bluetooth module to sleep and wakes up the module by driving RTS low for a certain length of time; if autoRTS prevents MCR writes from driving RTS, then the wake up never happens. (see drivers/bluetooth/hci_ath.c : ath_wakeup_ar3k() for the equally broken workaround of turning off CRTSCTS via an internal tty core function which is going away soon).

The reason why TI 16c750-based AFE doesn't have to bother with this is because, on that hardware, the MCR RTS bit overrides the autoRTS state; ie., RTS = MCR_RTS & autoRTS.

If your hardware treats the two states orthogonally then you'll need to turn off autoRTS mode if TIOCM_RTS is being cleared.
The amba-pl011.c driver does this; see drivers/tty/serial/amba-pl011.c:
pl011_set_mctrl().

Regards,
Peter Hurley

#3 lore raw
Quoted 36 lines · Peter Hurley
Quoted 15 lines · Johannes Thumshirn

Hi,

We have problem with automatic flow control (i.e. auto RTS/CTS handshaking) in our uart driver (men_z135_uart.c). It's probably less a technical but a problem with me understanding the API.

I active the hardware auto flow control feature on the CRTSCTS flag in my uart_ops->set_termios() function. But then the RTS flag is set on every call of the uart_ops->set_mctrl() function, this seems to confuse the hardware. Is there a way to tell the tty layer that flow control is handled solely by hardware? I.e. is there a way of telling serial core to leave out the calls to uart_set_mctrl()/uart_clear_mctrl() in uart_throttle()/uart_unthrottle(), or is setting UPF_FLOW_HARD and then implementing a dummy port->ops->{un}throttle() the correct way?

Quoted 3 lines

Are there any drivers that use a hardware's automatic flow control feature I can use as an example? A fast grep on AFE reveals some spots, but I can't really find a difference to my implementation.

uart_throttle()/uart_unthrottle() is essentially broken.

If the RTS pin is driveable, then the UART driver must respond to TIOCM_RTS set and clear in the ->set_mctrl() handler, regardless of any mode selected in termios or other mode such as autoRTS.

This requirement exists because both userspace and other kernel drivers may want to drive RTS for their own purposes.

For example, a bluetooth UART HCI may allow the bluetooth module to sleep and wakes up the module by driving RTS low for a certain length of time; if autoRTS prevents MCR writes from driving RTS, then the wake up never happens. (see drivers/bluetooth/hci_ath.c : ath_wakeup_ar3k() for the equally broken workaround of turning off CRTSCTS via an internal tty core function which is going away soon).

Quoted 8 lines

The reason why TI 16c750-based AFE doesn't have to bother with this is because, on that hardware, the MCR RTS bit overrides the autoRTS state; ie., RTS = MCR_RTS & autoRTS.

If your hardware treats the two states orthogonally then you'll need to turn off autoRTS mode if TIOCM_RTS is being cleared.
The amba-pl011.c driver does this; see drivers/tty/serial/amba-pl011.c:
pl011_set_mctrl().

Thanks for the info.

We've actually found the problem. When using auto flow control we need to disable the modem status IRQs, in order to work.

The only problem that arises here is, when the modem status IRQs are disabled the uart_ops->start_tx() isn't called anymore. But there should be work arounds available.

Thanks,
Johannes

#4 lore raw
Quoted 46 lines · Johannes Thumshirn
Quoted 36 lines · Peter Hurley
Quoted 15 lines · Johannes Thumshirn

Hi,

We have problem with automatic flow control (i.e. auto RTS/CTS handshaking) in our uart driver (men_z135_uart.c). It's probably less a technical but a problem with me understanding the API.

I active the hardware auto flow control feature on the CRTSCTS flag in my uart_ops->set_termios() function. But then the RTS flag is set on every call of the uart_ops->set_mctrl() function, this seems to confuse the hardware. Is there a way to tell the tty layer that flow control is handled solely by hardware? I.e. is there a way of telling serial core to leave out the calls to uart_set_mctrl()/uart_clear_mctrl() in uart_throttle()/uart_unthrottle(), or is setting UPF_FLOW_HARD and then implementing a dummy port->ops->{un}throttle() the correct way?

Quoted 3 lines

Are there any drivers that use a hardware's automatic flow control feature I can use as an example? A fast grep on AFE reveals some spots, but I can't really find a difference to my implementation.

uart_throttle()/uart_unthrottle() is essentially broken.

If the RTS pin is driveable, then the UART driver must respond to TIOCM_RTS set and clear in the ->set_mctrl() handler, regardless of any mode selected in termios or other mode such as autoRTS.

This requirement exists because both userspace and other kernel drivers may want to drive RTS for their own purposes.

For example, a bluetooth UART HCI may allow the bluetooth module to sleep and wakes up the module by driving RTS low for a certain length of time; if autoRTS prevents MCR writes from driving RTS, then the wake up never happens. (see drivers/bluetooth/hci_ath.c : ath_wakeup_ar3k() for the equally broken workaround of turning off CRTSCTS via an internal tty core function which is going away soon).

Quoted 8 lines

The reason why TI 16c750-based AFE doesn't have to bother with this is because, on that hardware, the MCR RTS bit overrides the autoRTS state; ie., RTS = MCR_RTS & autoRTS.

If your hardware treats the two states orthogonally then you'll need to turn off autoRTS mode if TIOCM_RTS is being cleared.
The amba-pl011.c driver does this; see drivers/tty/serial/amba-pl011.c:
pl011_set_mctrl().

Quoted 4 lines

Thanks for the info.

We've actually found the problem. When using auto flow control we need to disable the modem status IRQs, in order to work.

So the UART still raises modem status interrupts for DCTS when autoCTS is on?

Quoted 3 lines

The only problem that arises here is, when the modem status IRQs are disabled the uart_ops->start_tx() isn't called anymore. But there should be work arounds available.

Almost certainly this is because ->hw_stopped has been set. The serial core does this in two places (besides uart_handle_cts_change()):
uart_port_startup() after initializing the port and, in uart_set_termios(), which, if you set UPF_HARD_FLOW, the serial core will skip.

Regards,
Peter Hurley

[Note: there's been some changes to flow control for 3.18; hw_stopped was moved to uart_port].

#5 lore raw
Quoted 63 lines · Peter Hurley
Quoted 46 lines · Johannes Thumshirn
Quoted 36 lines · Peter Hurley
Quoted 15 lines · Johannes Thumshirn

Hi,

We have problem with automatic flow control (i.e. auto RTS/CTS handshaking) in our uart driver (men_z135_uart.c). It's probably less a technical but a problem with me understanding the API.

I active the hardware auto flow control feature on the CRTSCTS flag in my uart_ops->set_termios() function. But then the RTS flag is set on every call of the uart_ops->set_mctrl() function, this seems to confuse the hardware. Is there a way to tell the tty layer that flow control is handled solely by hardware? I.e. is there a way of telling serial core to leave out the calls to uart_set_mctrl()/uart_clear_mctrl() in uart_throttle()/uart_unthrottle(), or is setting UPF_FLOW_HARD and then implementing a dummy port->ops->{un}throttle() the correct way?

Quoted 3 lines

Are there any drivers that use a hardware's automatic flow control feature I can use as an example? A fast grep on AFE reveals some spots, but I can't really find a difference to my implementation.

uart_throttle()/uart_unthrottle() is essentially broken.

If the RTS pin is driveable, then the UART driver must respond to TIOCM_RTS set and clear in the ->set_mctrl() handler, regardless of any mode selected in termios or other mode such as autoRTS.

This requirement exists because both userspace and other kernel drivers may want to drive RTS for their own purposes.

For example, a bluetooth UART HCI may allow the bluetooth module to sleep and wakes up the module by driving RTS low for a certain length of time; if autoRTS prevents MCR writes from driving RTS, then the wake up never happens. (see drivers/bluetooth/hci_ath.c : ath_wakeup_ar3k() for the equally broken workaround of turning off CRTSCTS via an internal tty core function which is going away soon).

Quoted 8 lines

The reason why TI 16c750-based AFE doesn't have to bother with this is because, on that hardware, the MCR RTS bit overrides the autoRTS state; ie., RTS = MCR_RTS & autoRTS.

If your hardware treats the two states orthogonally then you'll need to turn off autoRTS mode if TIOCM_RTS is being cleared.
The amba-pl011.c driver does this; see drivers/tty/serial/amba-pl011.c:
pl011_set_mctrl().

Quoted 4 lines

Thanks for the info.

We've actually found the problem. When using auto flow control we need to disable the modem status IRQs, in order to work.

So the UART still raises modem status interrupts for DCTS when autoCTS is on?

Quoted 3 lines

The only problem that arises here is, when the modem status IRQs are disabled the uart_ops->start_tx() isn't called anymore. But there should be work arounds available.

Almost certainly this is because ->hw_stopped has been set. The serial core does this in two places (besides uart_handle_cts_change()):
uart_port_startup() after initializing the port and, in uart_set_termios(), which, if you set UPF_HARD_FLOW, the serial core will skip.

Quoted 6 lines

Regards,
Peter Hurley

[Note: there's been some changes to flow control for 3.18; hw_stopped was moved to uart_port].

Sorry for the late reply, I've been a bit busy.

We've found a solution to the problem and I'll post a patch for review in a few days.

Thanks again,
Johannes