[ntp:questions] Realistic Performance Expectation for GPS PPS fed ntpd jitter

Matt Corallo ntp-lists at mattcorallo.com
Thu Oct 15 19:51:20 UTC 2020


I didn't say my setup was optimal, only that the IRQ processing and UART poll time is likely not your issue, as you note 
the IRQ jitter is more likely to be the culprit (though in my case there is no level shifting going on).

Patch below against 5.7.10, though I was lazy and only intended to make sure it works for the 8250-based UART in my box, 
YMMV, apologies in advance that email will almost certainly break lines in it. Its really much more trivial than you 
were thinking :)

Matt

commit 85aa50c40dae86b2d5051902e72fc1b18c1c8563
Author: Matt Corallo <git at bluematt.me>
Date:   Sun Sep 27 23:02:24 2020 -0400

     pass interrupt timestamp through to pps-ldisc

diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index 4fd0cbf7f931..0f4f55fd6d4c 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -15,12 +15,15 @@

  #define PPS_TTY_MAGIC		0x0001

-static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
+static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, struct system_time_snapshot *irq_ts)
  {
  	struct pps_device *pps;
  	struct pps_event_time ts;

-	pps_get_ts(&ts);
+	if (irq_ts == NULL)
+		pps_get_ts(&ts);
+	else
+		sys_snap_to_pps_ev(irq_ts, &ts);

  	pps = pps_lookup_dev(tty);
  	/*
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 9548d3f8fc8e..54c92902c960 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -111,6 +111,9 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
  	struct list_head *l, *end = NULL;
  	int pass_counter = 0, handled = 0;

+	struct system_time_snapshot ts;
+	ktime_get_snapshot(&ts);
+
  	pr_debug("%s(%d): start\n", __func__, irq);

  	spin_lock(&i->lock);
@@ -123,7 +126,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
  		up = list_entry(l, struct uart_8250_port, list);
  		port = &up->port;

-		if (port->handle_irq(port)) {
+		if (port->handle_irq(port, &ts)) {
  			handled = 1;
  			end = NULL;
  		} else if (end == NULL)
@@ -258,7 +261,7 @@ static void serial8250_timeout(struct timer_list *t)
  {
  	struct uart_8250_port *up = from_timer(up, t, timer);

-	up->port.handle_irq(&up->port);
+	up->port.handle_irq(&up->port, NULL);
  	mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
  }

diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index aab3cccc6789..d9d67fc275d4 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -219,7 +219,7 @@ static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
  }


-static int dw8250_handle_irq(struct uart_port *p)
+static int dw8250_handle_irq(struct uart_port *p, struct system_time_snapshot *ts)
  {
  	struct uart_8250_port *up = up_to_u8250p(p);
  	struct dw8250_data *d = to_dw8250_data(p->private_data);
@@ -247,7 +247,7 @@ static int dw8250_handle_irq(struct uart_port *p)
  		spin_unlock_irqrestore(&p->lock, flags);
  	}

-	if (serial8250_handle_irq(p, iir))
+	if (serial8250_handle_irq(p, iir, ts))
  		return 1;

  	if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
index efa0515139f8..78dab30a9c33 100644
--- a/drivers/tty/serial/8250/8250_mid.c
+++ b/drivers/tty/serial/8250/8250_mid.c
@@ -73,7 +73,7 @@ static int pnw_setup(struct mid8250 *mid, struct uart_port *p)
  	return 0;
  }

-static int tng_handle_irq(struct uart_port *p)
+static int tng_handle_irq(struct uart_port *p, struct system_time_snapshot *ts)
  {
  	struct mid8250 *mid = p->private_data;
  	struct uart_8250_port *up = up_to_u8250p(p);
@@ -100,7 +100,7 @@ static int tng_handle_irq(struct uart_port *p)
  		ret |= hsu_dma_do_irq(chip, mid->dma_index * 2, status);

  	/* UART */
-	ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+	ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR), ts);
  	return IRQ_RETVAL(ret);
  }

@@ -124,7 +124,7 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
  	return 0;
  }

-static int dnv_handle_irq(struct uart_port *p)
+static int dnv_handle_irq(struct uart_port *p, struct system_time_snapshot *ts)
  {
  	struct mid8250 *mid = p->private_data;
  	struct uart_8250_port *up = up_to_u8250p(p);
@@ -149,7 +149,7 @@ static int dnv_handle_irq(struct uart_port *p)
  			ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status);
  	}
  	if (fisr & BIT(0))
-		ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+		ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR), ts);
  	return IRQ_RETVAL(ret);
  }

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 4d83c85a7389..310688f874f0 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -452,7 +452,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
  	outb(value, p->iobase + offset);
  }

-static int serial8250_default_handle_irq(struct uart_port *port);
+static int serial8250_default_handle_irq(struct uart_port *port, struct system_time_snapshot *ts);

  static void set_io_from_upio(struct uart_port *p)
  {
@@ -1838,7 +1838,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
  EXPORT_SYMBOL_GPL(serial8250_tx_chars);

  /* Caller holds uart port lock */
-unsigned int serial8250_modem_status(struct uart_8250_port *up)
+unsigned int serial8250_modem_status(struct uart_8250_port *up, struct system_time_snapshot *ts)
  {
  	struct uart_port *port = &up->port;
  	unsigned int status = serial_in(up, UART_MSR);
@@ -1852,7 +1852,7 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up)
  		if (status & UART_MSR_DDSR)
  			port->icount.dsr++;
  		if (status & UART_MSR_DDCD)
-			uart_handle_dcd_change(port, status & UART_MSR_DCD);
+			uart_handle_dcd_change(port, status & UART_MSR_DCD, ts);
  		if (status & UART_MSR_DCTS)
  			uart_handle_cts_change(port, status & UART_MSR_CTS);

@@ -1878,7 +1878,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
  /*
   * This handles the interrupt from one port.
   */
-int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir, struct system_time_snapshot *ts)
  {
  	unsigned char status;
  	unsigned long flags;
@@ -1909,7 +1909,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
  		if (!up->dma || handle_rx_dma(up, iir))
  			status = serial8250_rx_chars(up, status);
  	}
-	serial8250_modem_status(up);
+	serial8250_modem_status(up, ts);
  	if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) &&
  		(up->ier & UART_IER_THRI))
  		serial8250_tx_chars(up);
@@ -1919,7 +1919,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
  }
  EXPORT_SYMBOL_GPL(serial8250_handle_irq);

-static int serial8250_default_handle_irq(struct uart_port *port)
+static int serial8250_default_handle_irq(struct uart_port *port, struct system_time_snapshot *ts)
  {
  	struct uart_8250_port *up = up_to_u8250p(port);
  	unsigned int iir;
@@ -1928,7 +1928,7 @@ static int serial8250_default_handle_irq(struct uart_port *port)
  	serial8250_rpm_get(up);

  	iir = serial_port_in(port, UART_IIR);
-	ret = serial8250_handle_irq(port, iir);
+	ret = serial8250_handle_irq(port, iir, ts);

  	serial8250_rpm_put(up);
  	return ret;
@@ -1940,7 +1940,7 @@ static int serial8250_default_handle_irq(struct uart_port *port)
   * the IIR register. In this case, the THRE interrupt indicates the FIFO
   * has space available. Load it up with tx_loadsz bytes.
   */
-static int serial8250_tx_threshold_handle_irq(struct uart_port *port)
+static int serial8250_tx_threshold_handle_irq(struct uart_port *port, struct system_time_snapshot *ts)
  {
  	unsigned long flags;
  	unsigned int iir = serial_port_in(port, UART_IIR);
@@ -1955,7 +1955,7 @@ static int serial8250_tx_threshold_handle_irq(struct uart_port *port)
  	}

  	iir = serial_port_in(port, UART_IIR);
-	return serial8250_handle_irq(port, iir);
+	return serial8250_handle_irq(port, iir, ts);
  }

  static unsigned int serial8250_tx_empty(struct uart_port *port)
@@ -1983,7 +1983,7 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port)
  	unsigned int val;

  	serial8250_rpm_get(up);
-	status = serial8250_modem_status(up);
+	status = serial8250_modem_status(up, NULL);
  	serial8250_rpm_put(up);

  	val = serial8250_MSR_to_TIOCM(status);
@@ -3287,7 +3287,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
  	 *	while processing with interrupts off.
  	 */
  	if (up->msr_saved_flags)
-		serial8250_modem_status(up);
+		serial8250_modem_status(up, NULL);

  	if (locked)
  		spin_unlock_irqrestore(&port->lock, flags);
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index 3284f34e9dfe..8746f096c1d9 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -211,7 +211,7 @@ static void pl010_modem_status(struct uart_amba_port *uap)
  		return;

  	if (delta & UART01x_FR_DCD)
-		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
+		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD, NULL);

  	if (delta & UART01x_FR_DSR)
  		uap->port.icount.dsr++;
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 458fc3d9d48c..86c825776a78 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1433,7 +1433,7 @@ static void pl011_modem_status(struct uart_amba_port *uap)
  		return;

  	if (delta & UART01x_FR_DCD)
-		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
+		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD, NULL);

  	if (delta & uap->vendor->fr_dsr)
  		uap->port.icount.dsr++;
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 8d7080efad9b..dfaf2c695062 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1388,7 +1388,7 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
  			if (status_change & ATMEL_US_DSR)
  				port->icount.dsr++;
  			if (status_change & ATMEL_US_DCD)
-				uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
+				uart_handle_dcd_change(port, !(status & ATMEL_US_DCD, NULL));
  			if (status_change & ATMEL_US_CTS)
  				uart_handle_cts_change(port, !(status & ATMEL_US_CTS));

diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 5674da2b76f0..c3e3c0d9ed04 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -381,7 +381,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
  					       estat & UART_EXTINP_CTS_MASK);
  		if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD))
  			uart_handle_dcd_change(port,
-					       estat & UART_EXTINP_DCD_MASK);
+					       estat & UART_EXTINP_DCD_MASK, NULL);
  	}

  	spin_unlock(&port->lock);
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 624f3d541c68..d76934e59402 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -678,7 +678,7 @@ static inline void check_modem_status(struct icom_port *icom_port)
  			icom_port->uart_port.icount.dsr++;
  		if (delta_status & ICOM_DCD)
  			uart_handle_dcd_change(&icom_port->uart_port,
-					       delta_status & ICOM_DCD);
+					       delta_status & ICOM_DCD, NULL);
  		if (delta_status & ICOM_CTS)
  			uart_handle_cts_change(&icom_port->uart_port,
  					       delta_status & ICOM_CTS);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index d5979a8bdc40..dc7d0d3c876f 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -861,7 +861,7 @@ static void imx_uart_mctrl_check(struct imx_port *sport)
  	if (changed & TIOCM_DSR)
  		sport->port.icount.dsr++;
  	if (changed & TIOCM_CAR)
-		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR, NULL);
  	if (changed & TIOCM_CTS)
  		uart_handle_cts_change(&sport->port, status & TIOCM_CTS);

diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index 86fff69d7e7c..280da62863d3 100644
--- a/drivers/tty/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
@@ -341,7 +341,7 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
  		 */
  		if ((status ^ up->prev_status) ^ DCD)
  			uart_handle_dcd_change(&up->port,
-					       (status & DCD));
+					       (status & DCD), NULL);
  		if ((status ^ up->prev_status) ^ CTS)
  			uart_handle_cts_change(&up->port,
  					       (status & CTS));
diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c
index c061a7b7bd23..2ca5ddf044ee 100644
--- a/drivers/tty/serial/jsm/jsm_cls.c
+++ b/drivers/tty/serial/jsm/jsm_cls.c
@@ -514,9 +514,9 @@ static void cls_parse_modem(struct jsm_channel *ch, u8 signals)
  	msignals &= 0xf8;

  	if (msignals & UART_MSR_DDCD)
-		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
+		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD, NULL);
  	if (msignals & UART_MSR_DDSR)
-		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_CTS);
+		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_CTS, NULL);

  	if (msignals & UART_MSR_DCD)
  		ch->ch_mistat |= UART_MSR_DCD;
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index bf0e2a4cb0ce..ff92efe7f48e 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -567,7 +567,7 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
  	msignals &= 0xf8;

  	if (msignals & UART_MSR_DDCD)
-		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
+		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD, NULL);
  	if (msignals & UART_MSR_DDSR)
  		uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
  	if (msignals & UART_MSR_DCD)
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 4f53a4caabf6..d034b4a32e91 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -186,7 +186,7 @@ static void men_z135_handle_modem_status(struct men_z135_port *uart)

  	if (msr & MEN_Z135_MSR_DDCD)
  		uart_handle_dcd_change(&uart->port,
-				msr & MEN_Z135_MSR_DCD);
+				msr & MEN_Z135_MSR_DCD, NULL);
  	if (msr & MEN_Z135_MSR_DCTS)
  		uart_handle_cts_change(&uart->port,
  				msr & MEN_Z135_MSR_CTS);
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index af1700445251..6c89c6f4cdfd 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1491,7 +1491,7 @@ mpc5xxx_uart_process_int(struct uart_port *port)

  		status = psc_ops->get_ipcr(port);
  		if (status & MPC52xx_PSC_D_DCD)
-			uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
+			uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD), NULL);

  		if (status & MPC52xx_PSC_D_CTS)
  			uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index b784323a6a7b..8e87d220dc94 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -761,7 +761,7 @@ static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl)
  		if (mctrl_diff & TIOCM_DSR)
  			s->port.icount.dsr++;
  		if (mctrl_diff & TIOCM_CD)
-			uart_handle_dcd_change(&s->port, mctrl & TIOCM_CD);
+			uart_handle_dcd_change(&s->port, mctrl & TIOCM_CD, NULL);
  		if (mctrl_diff & TIOCM_CTS)
  			uart_handle_cts_change(&s->port, mctrl & TIOCM_CTS);

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index f7d6b3c9ea45..2622027da3ef 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -474,7 +474,7 @@ static unsigned int check_modem_status(struct uart_omap_port *up)
  			up->port.icount.dsr++;
  		if (status & UART_MSR_DDCD)
  			uart_handle_dcd_change
-				(&up->port, status & UART_MSR_DCD);
+				(&up->port, status & UART_MSR_DCD, NULL);
  		if (status & UART_MSR_DCTS)
  			uart_handle_cts_change
  				(&up->port, status & UART_MSR_CTS);
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index ba65a3bbd72a..3a64617e17ec 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -337,7 +337,7 @@ static void pmz_status_handle(struct uart_pmac_port *uap)
  		 */
  		if ((status ^ uap->prev_status) & DCD)
  			uart_handle_dcd_change(&uap->port,
-					       (status & DCD));
+					       (status & DCD), NULL);
  		if ((status ^ uap->prev_status) & CTS)
  			uart_handle_cts_change(&uap->port,
  					       !(status & CTS));
diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c
index 972d94e8d32b..de4c3eed1cb4 100644
--- a/drivers/tty/serial/pnx8xxx_uart.c
+++ b/drivers/tty/serial/pnx8xxx_uart.c
@@ -88,7 +88,7 @@ static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
  	if (changed & TIOCM_DSR)
  		sport->port.icount.dsr++;
  	if (changed & TIOCM_CAR)
-		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR, NULL);
  	if (changed & TIOCM_CTS)
  		uart_handle_cts_change(&sport->port, status & TIOCM_CTS);

diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 41319ef96fa6..cce8a46accf0 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -229,7 +229,7 @@ static inline void check_modem_status(struct uart_pxa_port *up)
  	if (status & UART_MSR_DDSR)
  		up->port.icount.dsr++;
  	if (status & UART_MSR_DDCD)
-		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD, NULL);
  	if (status & UART_MSR_DCTS)
  		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);

diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 75c2a22895f9..f665b49a9c28 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -98,7 +98,7 @@ static void sa1100_mctrl_check(struct sa1100_port *sport)
  	if (changed & TIOCM_DSR)
  		sport->port.icount.dsr++;
  	if (changed & TIOCM_CAR)
-		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR, NULL);
  	if (changed & TIOCM_CTS)
  		uart_handle_cts_change(&sport->port, status & TIOCM_CTS);

diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 8de8bac9c6c7..8d70250bdf49 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -819,7 +819,7 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u)
  		tup->uport.icount.dsr++;
  	/* We may only get DDCD when HW init and reset */
  	if (msr & UART_MSR_DDCD)
-		uart_handle_dcd_change(&tup->uport, msr & UART_MSR_DCD);
+		uart_handle_dcd_change(&tup->uport, msr & UART_MSR_DCD, NULL);
  	/* Will start/stop_tx accordingly */
  	if (msr & UART_MSR_DCTS)
  		uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 01cfeece0f16..b1fe859b6d64 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3059,7 +3059,7 @@ EXPORT_SYMBOL(uart_match_port);
   *
   *	Caller must hold uport->lock
   */
-void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
+void uart_handle_dcd_change(struct uart_port *uport, unsigned int status, struct system_time_snapshot *ts)
  {
  	struct tty_port *port = &uport->state->port;
  	struct tty_struct *tty = port->tty;
@@ -3071,7 +3071,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
  		ld = tty_ldisc_ref(tty);
  		if (ld) {
  			if (ld->ops->dcd_change)
-				ld->ops->dcd_change(tty, status);
+				ld->ops->dcd_change(tty, status, ts);
  			tty_ldisc_deref(ld);
  		}
  	}
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index fb4781292d40..4c8c8808d1ea 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -176,7 +176,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
  			port->icount.dsr++;

  		if (mctrl_diff & TIOCM_CD)
-			uart_handle_dcd_change(port, mctrl & TIOCM_CD);
+			uart_handle_dcd_change(port, mctrl & TIOCM_CD, NULL);

  		if (mctrl_diff & TIOCM_CTS)
  			uart_handle_cts_change(port, mctrl & TIOCM_CTS);
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index e35073e93a5b..b062861d2e57 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -89,10 +89,10 @@ static int receive_chars_getchar(struct uart_port *port)

  		if (c == CON_HUP) {
  			hung_up = 1;
-			uart_handle_dcd_change(port, 0);
+			uart_handle_dcd_change(port, 0, NULL);
  		} else if (hung_up) {
  			hung_up = 0;
-			uart_handle_dcd_change(port, 1);
+			uart_handle_dcd_change(port, 1, NULL);
  		}

  		if (port->state == NULL) {
@@ -135,7 +135,7 @@ static int receive_chars_read(struct uart_port *port)
  				bytes_read = 1;
  			} else if (stat == CON_HUP) {
  				hung_up = 1;
-				uart_handle_dcd_change(port, 0);
+				uart_handle_dcd_change(port, 0, NULL);
  				continue;
  			} else {
  				/* HV_EWOULDBLOCK, etc.  */
@@ -145,7 +145,7 @@ static int receive_chars_read(struct uart_port *port)

  		if (hung_up) {
  			hung_up = 0;
-			uart_handle_dcd_change(port, 1);
+			uart_handle_dcd_change(port, 1, NULL);
  		}

  		if (port->sysrq != 0 &&  *con_read_page) {
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 1eb703c980e0..8f761f95000c 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -288,7 +288,7 @@ static void check_status(struct uart_sunsab_port *up,
  {
  	if (stat->sreg.isr0 & SAB82532_ISR0_CDSC)
  		uart_handle_dcd_change(&up->port,
-				       !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD));
+				       !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD), NULL);

  	if (stat->sreg.isr1 & SAB82532_ISR1_CSC)
  		uart_handle_cts_change(&up->port,
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 8ce9a7a256e5..7a99f7f69d0c 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -443,7 +443,7 @@ static void check_modem_status(struct uart_sunsu_port *up)
  	if (status & UART_MSR_DDSR)
  		up->port.icount.dsr++;
  	if (status & UART_MSR_DDCD)
-		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD, NULL);
  	if (status & UART_MSR_DCTS)
  		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);

diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 103ab8c556e7..1e4f73199afc 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -439,7 +439,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
  		 */
  		if ((status ^ up->prev_status) ^ DCD)
  			uart_handle_dcd_change(&up->port,
-					       (status & DCD));
+					       (status & DCD), NULL);
  		if ((status ^ up->prev_status) ^ CTS)
  			uart_handle_cts_change(&up->port,
  					       (status & CTS));
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index eeb4b6568776..69e0bbc15a2b 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -359,7 +359,7 @@ static inline void check_modem_status(struct uart_port *port)
  	if ((msr & UART_MSR_ANY_DELTA) == 0)
  		return;
  	if (msr & UART_MSR_DDCD)
-		uart_handle_dcd_change(port, msr & UART_MSR_DCD);
+		uart_handle_dcd_change(port, msr & UART_MSR_DCD, NULL);
  	if (msr & UART_MSR_TERI)
  		port->icount.rng++;
  	if (msr & UART_MSR_DDSR)
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index 4b4f604646a7..70a6d8458f6f 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -677,7 +677,7 @@ static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
  					       zport->mctrl & TIOCM_CTS);
  		if (delta & TIOCM_CAR)
  			uart_handle_dcd_change(uport,
-					       zport->mctrl & TIOCM_CAR);
+					       zport->mctrl & TIOCM_CAR, NULL);
  		if (delta & TIOCM_RNG)
  			uport->icount.dsr++;
  		if (delta & TIOCM_DSR)
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 5cdf180cda23..595c1354fa83 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -619,7 +619,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *port,

  		if (ld) {
  			if (ld->ops->dcd_change)
-				ld->ops->dcd_change(tty, status);
+				ld->ops->dcd_change(tty, status, NULL);
  			tty_ldisc_deref(ld);
  		}
  	}
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
index 78c8ac4951b5..f9663dccaae7 100644
--- a/include/linux/pps_kernel.h
+++ b/include/linux/pps_kernel.h
@@ -97,15 +97,20 @@ static inline void timespec_to_pps_ktime(struct pps_ktime *kt,
  	kt->nsec = ts.tv_nsec;
  }

+static inline void sys_snap_to_pps_ev(struct system_time_snapshot *snap, struct pps_event_time *ts)
+{
+	ts->ts_real = ktime_to_timespec64(snap->real);
+#ifdef CONFIG_NTP_PPS
+	ts->ts_raw = ktime_to_timespec64(snap->raw);
+#endif
+}
+
  static inline void pps_get_ts(struct pps_event_time *ts)
  {
  	struct system_time_snapshot snap;

  	ktime_get_snapshot(&snap);
-	ts->ts_real = ktime_to_timespec64(snap.real);
-#ifdef CONFIG_NTP_PPS
-	ts->ts_raw = ktime_to_timespec64(snap.raw);
-#endif
+	sys_snap_to_pps_ev(&snap, ts);
  }

  /* Subtract known time delay from PPS event time(s) */
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 6545f8cfc8fa..d741c1335f70 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -10,6 +10,7 @@
  #include <linux/serial_core.h>
  #include <linux/serial_reg.h>
  #include <linux/platform_device.h>
+#include <linux/timekeeping.h>

  /*
   * This is the platform device platform_data structure
@@ -36,7 +37,7 @@ struct plat_serial8250_port {
  	void		(*set_ldisc)(struct uart_port *,
  				     struct ktermios *);
  	unsigned int	(*get_mctrl)(struct uart_port *);
-	int		(*handle_irq)(struct uart_port *);
+	int		(*handle_irq)(struct uart_port *, struct system_time_snapshot *);
  	void		(*pm)(struct uart_port *, unsigned int state,
  			      unsigned old);
  	void		(*handle_break)(struct uart_port *);
@@ -168,12 +169,12 @@ extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
  extern void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
  				      unsigned int quot,
  				      unsigned int quot_frac);
-extern int fsl8250_handle_irq(struct uart_port *port);
-int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
+extern int fsl8250_handle_irq(struct uart_port *port, struct system_time_snapshot *ts);
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir, struct system_time_snapshot *ts);
  unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
  void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr);
  void serial8250_tx_chars(struct uart_8250_port *up);
-unsigned int serial8250_modem_status(struct uart_8250_port *up);
+unsigned int serial8250_modem_status(struct uart_8250_port *up, struct system_time_snapshot *ts);
  void serial8250_init_port(struct uart_8250_port *up);
  void serial8250_set_defaults(struct uart_8250_port *up);
  void serial8250_console_write(struct uart_8250_port *up, const char *s,
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 60b1160b6d06..74522a81f528 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -15,6 +15,7 @@
  #include <linux/spinlock.h>
  #include <linux/sched.h>
  #include <linux/tty.h>
+#include <linux/timekeeping.h>
  #include <linux/mutex.h>
  #include <linux/sysrq.h>
  #include <uapi/linux/serial_core.h>
@@ -126,7 +127,7 @@ struct uart_port {
  	void			(*shutdown)(struct uart_port *port);
  	void			(*throttle)(struct uart_port *port);
  	void			(*unthrottle)(struct uart_port *port);
-	int			(*handle_irq)(struct uart_port *);
+	int			(*handle_irq)(struct uart_port *, struct system_time_snapshot *);
  	void			(*pm)(struct uart_port *, unsigned int state,
  				      unsigned int old);
  	void			(*handle_break)(struct uart_port *);
@@ -453,7 +454,7 @@ static inline bool uart_softcts_mode(struct uart_port *uport)
   */

  extern void uart_handle_dcd_change(struct uart_port *uport,
-		unsigned int status);
+		unsigned int status, struct system_time_snapshot *ts);
  extern void uart_handle_cts_change(struct uart_port *uport,
  		unsigned int status);

diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index b1e6043e9917..7cab68d8cd3d 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -105,10 +105,12 @@
   *	seek to perform this action quickly but should wait until
   *	any pending driver I/O is completed.
   *
- * void (*dcd_change)(struct tty_struct *tty, unsigned int status)
+ * void (*dcd_change)(struct tty_struct *tty, unsigned int status,
+ *       struct system_time_snapshot *)
   *
   *	Tells the discipline that the DCD pin has changed its status.
   *	Used exclusively by the N_PPS (Pulse-Per-Second) line discipline.
+ *	May include a timestamp for when the interrupt fired.
   *
   * int	(*receive_buf2)(struct tty_struct *, const unsigned char *cp,
   *			char *fp, int count);
@@ -203,7 +205,7 @@ struct tty_ldisc_ops {
  	void	(*receive_buf)(struct tty_struct *, const unsigned char *cp,
  			       char *fp, int count);
  	void	(*write_wakeup)(struct tty_struct *);
-	void	(*dcd_change)(struct tty_struct *, unsigned int);
+	void	(*dcd_change)(struct tty_struct *, unsigned int, struct system_time_snapshot *);
  	int	(*receive_buf2)(struct tty_struct *, const unsigned char *cp,
  				char *fp, int count);



More information about the questions mailing list