[LinuxPPS] [SOLVED] linuxPPS stops working when NTP starts
George Spelvin
linux at horizon.com
Tue Nov 11 21:36:36 CET 2008
For a few months, I've been having the problem that /dev/pps0 stops
working while NTP has /dev/ttyS0 open. A few other people have reported
this problem as well. I finally figured out the problem.
It boils down to the definition of UART_ENABLE_MS in
include/linux/serial_core.h:568.
/*
* UART_ENABLE_MS - determine if port should enable modem status irqs
*/
#define UART_ENABLE_MS(port,cflag) ((port)->flags & UPF_HARDPPS_CD || \
(cflag) & CRTSCTS || \
!((cflag) & CLOCAL))
If this is false, the following code in serial8250_set_termios
(drivers/serial/8250.c:2188) clears UART_IER_MSI
/*
* CTS flow control flag and modem status interrupts
*/
up->ier &= ~UART_IER_MSI;
if (!(up->bugs & UART_BUG_NOMSR) &&
UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
Then, in check_modem_status, if UART_IER_MSI is clear, the delta
status bits aren't even examined:
unsigned int status = serial_in(up, UART_MSR);
status |= up->msr_saved_flags;
up->msr_saved_flags = 0;
if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
up->port.info != NULL) {
/* ... */
if (status & UART_MSR_DDCD)
uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
As verification, turning on crtscts makes pps start working again.
A simple fix would be to add the existence of ld->ops->dcd_change to
the UART_ENABLE_MS condition, but I'd have to ensure that
serial8250_set_termios is called on ldisc change.
Still to be figured out: Why linuxpps 5.x has trouble seeing short
status pulses that linuxpps 4.x had no trouble with.
I'm wondering if moving check_modem_status() up would help.
I'm about to recompile and test
static inline void
serial8250_handle_port(struct uart_8250_port *up)
{
unsigned int status;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
check_modem_status(up); /* NEW */
status = serial_inp(up, UART_LSR);
DEBUG_INTR("status = %x...", status);
if (status & (UART_LSR_DR | UART_LSR_BI)) {
receive_chars(up, &status);
check_modem_status(up); /* MOVED */
}
if (status & UART_LSR_THRE)
transmit_chars(up);
spin_unlock_irqrestore(&up->port.lock, flags);
}
More information about the LinuxPPS
mailing list