netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments
@ 2021-12-16 20:01 Jonathan Lemon
  2021-12-16 20:01 ` [PATCH 2/5] ptp: ocp: Expose clock status drift and offset Jonathan Lemon
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Jonathan Lemon @ 2021-12-16 20:01 UTC (permalink / raw)
  To: netdev, davem, kuba; +Cc: kernel-team

In ("ptp: ocp: Have FPGA fold in ns adjustment for adjtime."), the
ns adjustment was written to the FPGA register, so the clock could
accurately perform adjustments.

However, the adjtime() call passes in a s64, while the clock adjustment
registers use a s32.  When trying to perform adjustments with a large
value (37 sec), things fail.

Examine the incoming delta, and if larger than 1 sec, use the original
(coarse) adjustment method.  If smaller than 1 sec, then allow the
FPGA to fold in the changes over a 1 second window.

Fixes: 2d97ed56f671 ("ptp: ocp: Have FPGA fold in ns adjustment for adjtime.")
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 0f1b5a7d2a89..17ad5f0d13b2 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -607,7 +607,7 @@ ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts)
 }
 
 static void
-__ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u64 adj_val)
+__ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u32 adj_val)
 {
 	u32 select, ctrl;
 
@@ -615,7 +615,7 @@ __ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u64 adj_val)
 	iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select);
 
 	iowrite32(adj_val, &bp->reg->offset_ns);
-	iowrite32(adj_val & 0x7f, &bp->reg->offset_window_ns);
+	iowrite32(NSEC_PER_SEC, &bp->reg->offset_window_ns);
 
 	ctrl = OCP_CTRL_ADJUST_OFFSET | OCP_CTRL_ENABLE;
 	iowrite32(ctrl, &bp->reg->ctrl);
@@ -624,6 +624,22 @@ __ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u64 adj_val)
 	iowrite32(select >> 16, &bp->reg->select);
 }
 
+static void
+ptp_ocp_adjtime_coarse(struct ptp_ocp *bp, u64 delta_ns)
+{
+	struct timespec64 ts;
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	err = __ptp_ocp_gettime_locked(bp, &ts, NULL);
+	if (likely(!err)) {
+		timespec64_add_ns(&ts, delta_ns);
+		__ptp_ocp_settime_locked(bp, &ts);
+	}
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
 static int
 ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
 {
@@ -631,6 +647,11 @@ ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
 	unsigned long flags;
 	u32 adj_ns, sign;
 
+	if (delta_ns > NSEC_PER_SEC || -delta_ns > NSEC_PER_SEC) {
+		ptp_ocp_adjtime_coarse(bp, delta_ns);
+		return 0;
+	}
+
 	sign = delta_ns < 0 ? BIT(31) : 0;
 	adj_ns = sign ? -delta_ns : delta_ns;
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] ptp: ocp: Expose clock status drift and offset
  2021-12-16 20:01 [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jonathan Lemon
@ 2021-12-16 20:01 ` Jonathan Lemon
  2021-12-16 20:01 ` [PATCH 3/5] ptp: ocp: add tod_correction attribute Jonathan Lemon
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Lemon @ 2021-12-16 20:01 UTC (permalink / raw)
  To: netdev, davem, kuba; +Cc: kernel-team

From: Vadim Fedorenko <vadfed@fb.com>

Monitoring of clock variance could be done through checking
the offset and the drift updates that are applied to atomic
clocks. Expose these values as attributes for timecard.

Signed-off-by: Vadim Fedorenko <vadfed@fb.com>
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 17ad5f0d13b2..2ac5ef54fada 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -52,6 +52,8 @@ struct ocp_reg {
 	u32	servo_offset_i;
 	u32	servo_drift_p;
 	u32	servo_drift_i;
+	u32	status_offset;
+	u32	status_drift;
 };
 
 #define OCP_CTRL_ENABLE		BIT(0)
@@ -1974,6 +1976,36 @@ available_clock_sources_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(available_clock_sources);
 
+static ssize_t
+clock_status_drift_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	u32 val;
+	int res;
+
+	val = ioread32(&bp->reg->status_drift);
+	res = (val & ~INT_MAX) ? -1 : 1;
+	res *= (val & INT_MAX);
+	return sysfs_emit(buf, "%d\n", res);
+}
+static DEVICE_ATTR_RO(clock_status_drift);
+
+static ssize_t
+clock_status_offset_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	u32 val;
+	int res;
+
+	val = ioread32(&bp->reg->status_offset);
+	res = (val & ~INT_MAX) ? -1 : 1;
+	res *= (val & INT_MAX);
+	return sysfs_emit(buf, "%d\n", res);
+}
+static DEVICE_ATTR_RO(clock_status_offset);
+
 static struct attribute *timecard_attrs[] = {
 	&dev_attr_serialnum.attr,
 	&dev_attr_gnss_sync.attr,
@@ -1985,6 +2017,8 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_sma4.attr,
 	&dev_attr_available_sma_inputs.attr,
 	&dev_attr_available_sma_outputs.attr,
+	&dev_attr_clock_status_drift.attr,
+	&dev_attr_clock_status_offset.attr,
 	&dev_attr_irig_b_mode.attr,
 	&dev_attr_utc_tai_offset.attr,
 	&dev_attr_ts_window_adjust.attr,
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] ptp: ocp: add tod_correction attribute
  2021-12-16 20:01 [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jonathan Lemon
  2021-12-16 20:01 ` [PATCH 2/5] ptp: ocp: Expose clock status drift and offset Jonathan Lemon
@ 2021-12-16 20:01 ` Jonathan Lemon
  2021-12-16 20:01 ` [PATCH 4/5] ptp: ocp: adjust utc_tai_offset to TOD info Jonathan Lemon
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Lemon @ 2021-12-16 20:01 UTC (permalink / raw)
  To: netdev, davem, kuba; +Cc: kernel-team

From: Vadim Fedorenko <vadfed@fb.com>

TOD correction register is used to compensate for leap seconds in
different domains. Export it as attribute with write access.

Signed-off-by: Vadim Fedorenko <vadfed@fb.com>
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 2ac5ef54fada..2383d1024f0f 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -2006,6 +2006,46 @@ clock_status_offset_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(clock_status_offset);
 
+static ssize_t
+tod_correction_show(struct device *dev,
+		    struct device_attribute *attr, char *buf)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	u32 val;
+	int res;
+
+	val = ioread32(&bp->tod->adj_sec);
+	res = (val & ~INT_MAX) ? -1 : 1;
+	res *= (val & INT_MAX);
+	return sysfs_emit(buf, "%d\n", res);
+}
+
+static ssize_t
+tod_correction_store(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct ptp_ocp *bp = dev_get_drvdata(dev);
+	unsigned long flags;
+	int err, res;
+	u32 val = 0;
+
+	err = kstrtos32(buf, 0, &res);
+	if (err)
+		return err;
+	if (res < 0) {
+		res *= -1;
+		val |= BIT(31);
+	}
+	val |= res;
+
+	spin_lock_irqsave(&bp->lock, flags);
+	iowrite32(val, &bp->tod->adj_sec);
+	spin_unlock_irqrestore(&bp->lock, flags);
+
+	return count;
+}
+static DEVICE_ATTR_RW(tod_correction);
+
 static struct attribute *timecard_attrs[] = {
 	&dev_attr_serialnum.attr,
 	&dev_attr_gnss_sync.attr,
@@ -2022,6 +2062,7 @@ static struct attribute *timecard_attrs[] = {
 	&dev_attr_irig_b_mode.attr,
 	&dev_attr_utc_tai_offset.attr,
 	&dev_attr_ts_window_adjust.attr,
+	&dev_attr_tod_correction.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(timecard);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] ptp: ocp: adjust utc_tai_offset to TOD info
  2021-12-16 20:01 [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jonathan Lemon
  2021-12-16 20:01 ` [PATCH 2/5] ptp: ocp: Expose clock status drift and offset Jonathan Lemon
  2021-12-16 20:01 ` [PATCH 3/5] ptp: ocp: add tod_correction attribute Jonathan Lemon
@ 2021-12-16 20:01 ` Jonathan Lemon
  2021-12-16 20:01 ` [PATCH 5/5] ptp: ocp: export board info via devlink Jonathan Lemon
  2021-12-18  3:10 ` [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jakub Kicinski
  4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Lemon @ 2021-12-16 20:01 UTC (permalink / raw)
  To: netdev, davem, kuba; +Cc: kernel-team

From: Vadim Fedorenko <vadfed@fb.com>

utc_tai_offset is used to correct IRIG, DCF and NMEA outputs and is
set during initialisation but is not corrected during leap second
announce event. Add watchdog code to control this correction.

Signed-off-by: Vadim Fedorenko <vadfed@fb.com>
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 51 ++++++++++++++++++++++++++-----------------
 1 file changed, 31 insertions(+), 20 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 2383d1024f0f..dc4d07b04320 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -761,12 +761,31 @@ __ptp_ocp_clear_drift_locked(struct ptp_ocp *bp)
 	iowrite32(select >> 16, &bp->reg->select);
 }
 
+static void
+ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	bp->utc_tai_offset = val;
+
+	if (bp->irig_out)
+		iowrite32(val, &bp->irig_out->adj_sec);
+	if (bp->dcf_out)
+		iowrite32(val, &bp->dcf_out->adj_sec);
+	if (bp->nmea_out)
+		iowrite32(val, &bp->nmea_out->adj_sec);
+
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
 static void
 ptp_ocp_watchdog(struct timer_list *t)
 {
 	struct ptp_ocp *bp = from_timer(bp, t, watchdog);
 	unsigned long flags;
-	u32 status;
+	u32 status, utc_offset;
 
 	status = ioread32(&bp->pps_to_clk->status);
 
@@ -783,6 +802,17 @@ ptp_ocp_watchdog(struct timer_list *t)
 		bp->gnss_lost = 0;
 	}
 
+	/* if GNSS provides correct data we can rely on
+	 * it to get leap second information
+	 */
+	if (bp->tod) {
+		status = ioread32(&bp->tod->utc_status);
+		utc_offset = status & TOD_STATUS_UTC_MASK;
+		if (status & TOD_STATUS_UTC_VALID &&
+		    utc_offset != bp->utc_tai_offset)
+			ptp_ocp_utc_distribute(bp, utc_offset);
+	}
+
 	mod_timer(&bp->watchdog, jiffies + HZ);
 }
 
@@ -851,25 +881,6 @@ ptp_ocp_init_clock(struct ptp_ocp *bp)
 	return 0;
 }
 
-static void
-ptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&bp->lock, flags);
-
-	bp->utc_tai_offset = val;
-
-	if (bp->irig_out)
-		iowrite32(val, &bp->irig_out->adj_sec);
-	if (bp->dcf_out)
-		iowrite32(val, &bp->dcf_out->adj_sec);
-	if (bp->nmea_out)
-		iowrite32(val, &bp->nmea_out->adj_sec);
-
-	spin_unlock_irqrestore(&bp->lock, flags);
-}
-
 static void
 ptp_ocp_tod_init(struct ptp_ocp *bp)
 {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] ptp: ocp: export board info via devlink
  2021-12-16 20:01 [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jonathan Lemon
                   ` (2 preceding siblings ...)
  2021-12-16 20:01 ` [PATCH 4/5] ptp: ocp: adjust utc_tai_offset to TOD info Jonathan Lemon
@ 2021-12-16 20:01 ` Jonathan Lemon
  2021-12-18  3:10 ` [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jakub Kicinski
  4 siblings, 0 replies; 6+ messages in thread
From: Jonathan Lemon @ 2021-12-16 20:01 UTC (permalink / raw)
  To: netdev, davem, kuba; +Cc: kernel-team

TimeCard has eeprom with manufacturer pre-defined information.
Export this via devlink interface.

Co-developed-by: Vadim Fedorenko <vadfed@fb.com>
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
 drivers/ptp/ptp_ocp.c | 71 +++++++++++++++++++++++++++++++------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index dc4d07b04320..8f235eef7521 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -203,6 +203,10 @@ struct ptp_ocp_ext_src {
 	int			irq_vec;
 };
 
+#define OCP_BOARD_MFR_LEN		8
+#define OCP_BOARD_ID_LEN		12
+#define OCP_SERIAL_LEN			6
+
 struct ptp_ocp {
 	struct pci_dev		*pdev;
 	struct device		dev;
@@ -237,8 +241,10 @@ struct ptp_ocp {
 	int			gnss2_port;
 	int			mac_port;	/* miniature atomic clock */
 	int			nmea_port;
-	u8			serial[6];
-	bool			has_serial;
+	u8			board_mfr[OCP_BOARD_MFR_LEN];
+	u8			board_id[OCP_BOARD_ID_LEN];
+	u8			serial[OCP_SERIAL_LEN];
+	bool			has_eeprom_data;
 	u32			pps_req_map;
 	int			flash_start;
 	u32			utc_tai_offset;
@@ -977,7 +983,7 @@ ptp_ocp_read_i2c(struct i2c_adapter *adap, u8 addr, u8 reg, u8 sz, u8 *data)
 }
 
 static void
-ptp_ocp_get_serial_number(struct ptp_ocp *bp)
+ptp_ocp_read_eeprom(struct ptp_ocp *bp)
 {
 	struct i2c_adapter *adap;
 	struct device *dev;
@@ -999,16 +1005,30 @@ ptp_ocp_get_serial_number(struct ptp_ocp *bp)
 		goto out;
 	}
 
-	err = ptp_ocp_read_i2c(adap, 0x58, 0x9A, 6, bp->serial);
-	if (err) {
-		dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", err);
-		goto out;
-	}
+	err = ptp_ocp_read_i2c(adap, 0x50, 0x7A,
+			       sizeof(bp->board_mfr), bp->board_mfr);
+	if (err)
+		goto read_fail;
 
-	bp->has_serial = true;
+	err = ptp_ocp_read_i2c(adap, 0x50, 0x44,
+			       sizeof(bp->board_id), bp->board_id);
+	if (err)
+		goto read_fail;
+
+	err = ptp_ocp_read_i2c(adap, 0x58, 0x9A,
+			       sizeof(bp->serial), bp->serial);
+	if (err)
+		goto read_fail;
+
+	bp->has_eeprom_data = true;
 
 out:
 	put_device(dev);
+	return;
+
+read_fail:
+	dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", err);
+	goto out;
 }
 
 static struct device *
@@ -1127,16 +1147,29 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
 			return err;
 	}
 
-	if (!bp->has_serial)
-		ptp_ocp_get_serial_number(bp);
-
-	if (bp->has_serial) {
-		sprintf(buf, "%pM", bp->serial);
-		err = devlink_info_serial_number_put(req, buf);
-		if (err)
-			return err;
+	if (!bp->has_eeprom_data) {
+		ptp_ocp_read_eeprom(bp);
+		if (!bp->has_eeprom_data)
+			return 0;
 	}
 
+	sprintf(buf, "%pM", bp->serial);
+	err = devlink_info_serial_number_put(req, buf);
+	if (err)
+		return err;
+
+	err = devlink_info_version_fixed_put(req,
+			DEVLINK_INFO_VERSION_GENERIC_BOARD_MANUFACTURE,
+			bp->board_mfr);
+	if (err)
+		return err;
+
+	err = devlink_info_version_fixed_put(req,
+			DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
+			bp->board_id);
+	if (err)
+		return err;
+
 	return 0;
 }
 
@@ -1828,8 +1861,8 @@ serialnum_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct ptp_ocp *bp = dev_get_drvdata(dev);
 
-	if (!bp->has_serial)
-		ptp_ocp_get_serial_number(bp);
+	if (!bp->has_eeprom_data)
+		ptp_ocp_read_eeprom(bp);
 
 	return sysfs_emit(buf, "%pM\n", bp->serial);
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments
  2021-12-16 20:01 [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jonathan Lemon
                   ` (3 preceding siblings ...)
  2021-12-16 20:01 ` [PATCH 5/5] ptp: ocp: export board info via devlink Jonathan Lemon
@ 2021-12-18  3:10 ` Jakub Kicinski
  4 siblings, 0 replies; 6+ messages in thread
From: Jakub Kicinski @ 2021-12-18  3:10 UTC (permalink / raw)
  To: Jonathan Lemon; +Cc: netdev, davem, kernel-team

On Thu, 16 Dec 2021 12:01:00 -0800 Jonathan Lemon wrote:
> In ("ptp: ocp: Have FPGA fold in ns adjustment for adjtime."), the
> ns adjustment was written to the FPGA register, so the clock could
> accurately perform adjustments.
> 
> However, the adjtime() call passes in a s64, while the clock adjustment
> registers use a s32.  When trying to perform adjustments with a large
> value (37 sec), things fail.
> 
> Examine the incoming delta, and if larger than 1 sec, use the original
> (coarse) adjustment method.  If smaller than 1 sec, then allow the
> FPGA to fold in the changes over a 1 second window.
> 
> Fixes: 2d97ed56f671 ("ptp: ocp: Have FPGA fold in ns adjustment for adjtime.")

This SHA does not exist upstream. Please separate the fixes from the
features. Please CC Richard on the patches.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-12-18  3:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-16 20:01 [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jonathan Lemon
2021-12-16 20:01 ` [PATCH 2/5] ptp: ocp: Expose clock status drift and offset Jonathan Lemon
2021-12-16 20:01 ` [PATCH 3/5] ptp: ocp: add tod_correction attribute Jonathan Lemon
2021-12-16 20:01 ` [PATCH 4/5] ptp: ocp: adjust utc_tai_offset to TOD info Jonathan Lemon
2021-12-16 20:01 ` [PATCH 5/5] ptp: ocp: export board info via devlink Jonathan Lemon
2021-12-18  3:10 ` [PATCH 1/5] ptp: ocp: Add ptp_ocp_adjtime_coarse for large adjustments Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).