This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

PROCESSOR-SDK-AM335X: ptp phy driver debug for motorcomm 1000M phy which supports 1588v2 & gptp(802.1as)

Part Number: PROCESSOR-SDK-AM335X

Hi experts,

now i am verifing ptp phy driver for motorcomm 1000M phy which supports 1588v2 & gptp(802.1as),

and facing some issues. pls help to give some suggestion. thank u a lot.

env description:
1. TI am335x disable TI CPU CPTS feature
2. linux kernel version 4.19.94-rt39-ga242ccf3f1
3. ptp4l application and cmd
(master: ./ptp4l -f automotive-master.cfg -i eth0 -m -l 7)
(slave: ./ptp4l -f automotive-slave.cfg -i eth0 -m -l 7)

ptp phy driver debug detail:
1. ptp4l sk_receive() 中 poll() timeout,
console log:
increasing tx_timestamp_timeout may correct this issue, but it is likely caused by a driver bug.
and check errno val: errno: -6

ptp4l source code snipper below:

int sk_receive(int fd, void *buf, int buflen,
struct address *addr, struct hw_timestamp *hwts, int flags)
{
      ...

if (flags == MSG_ERRQUEUE) {
struct pollfd pfd = { fd, sk_events, 0 };
res = poll(&pfd, 1, sk_tx_timeout);
if (res < 1) {
pr_err(res ? "poll for tx timestamp failed: %m" :
"timed out while polling for tx timestamp");
pr_err("increasing tx_timestamp_timeout may correct "
"this issue, but it is likely caused by a driver bug");
return -errno;
} else if (!(pfd.revents & sk_revents)) {
pr_err("poll for tx timestamp woke up on non ERR event");
return -1;
}
}

cnt = recvmsg(fd, &msg, flags);
...

2. linux kernel: sock_queue_err_skb() log :sk->sk_flags: 0x800100 => socket status is not SOCK_DEAD;
3. linux kernel: sock_queue_err_skb(), before invoking skb_queue_tail()
   check skb->sk->sk_error_queue.qlen: 0x0, after invoking skb_queue_tail(),
check skb->sk->sk_error_queue.qlen: 0x1, => skb attached hardware tx timestamp enqueued into err queue.

4. linux kernel: sk->sk_error_report(sk) callback sock_def_error_report() is called, 
   => err report is triggered to wake up the poll in ptp4l application.

5. master application(ptp4l) socket fd: 14
6. linux kernel: skb->tstamp assigned to ktime_get_real()
7. linux kernel: skb->ip_summed assigned to CHECKSUM_UNNECESSARY
8. linux kernel: before skb enqueued, skb->cb is cleared and
before skb_complete_tx_timestamp() called, skb->cb is cleared again.

9. strace -e ioctl ./ptp4l -i eth0 -m
   ioctl(SIOCSHWTSTAMP, ...) = 0

motorcomm phy ptp driver source code attached.

// SPDX-License-Identifier: GPL-2.0+
/*
 * drivers/net/phy/motorcomm.c
 *
 * Driver for Motorcomm PHYs
 *
 * Author: Jie Han<jie.han@motor-comm.com>
 *
 * Copyright (c) 2025 Motorcomm, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * Support Motorcomm Automotive Phys:
 * 1000M Phys: YT8011
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/phy.h>
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#else
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#endif

#include <linux/netdevice.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/ethtool.h>
#include <linux/list.h>
#include <linux/mii.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_classify.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/math64.h>
//#include <linux/skbuff.h>
//#include <linux/net.h>      // sock_put()
//#include <linux/socket.h>   // SCM_TSTAMP_SND
//#include <linux/skbuff.h>   // __skb_complete_tx_timestamp()
#include <net/sock.h>
//#include <linux/compiler-attributes.h>	//fallthrough
#include <linux/rtc.h>
#include <linux/time64.h>

//#include <linux/sock.h>
//debug (wrapper to unify log format)
#define DEBUG_PTP
#if defined DEBUG_PTP
#define dbg_ptp(fmt, ...) pr_info(fmt, ##__VA_ARGS__)
#else
#define dbg_ptp(fmt, ...)
#endif
	
#define YTPHY_LINUX_VERSION "2.2.45591"


#define MODULE_NAME "yt"
#define MOTORCOMM_PHY_ID_MASK		0xffffffff

#define PHY_ID_YT8011			0x4f51eb01

#define REG_PHY_SPEC_STATUS		0x11
#define REG_DEBUG_ADDR_OFFSET		0x1e
#define REG_DEBUG_DATA			0x1f
#define REG_MII_MMD_CTRL		0x0D
#define REG_MII_MMD_DATA		0x0E

#define YTXXXX_SPEED_MODE		0xc000
#define YTXXXX_SPEED_MODE_BIT		14
#define YTXXXX_DUPLEX_BIT		13
#define YTXXXX_LINK_STATUS_BIT		10

#define YTPHY_UTP_INTR_REG		0x12
#define YTPHY_UTP_INTR_STATUS_REG	0x13
#define YTPHY_INTR_LINK_STATUS		(BIT(11) | BIT(10))
#define YTPHY_REG_SPACE_UTP		0

#define YT801X_REG_SMI_MUX		0x9000
enum GPTP_ROLE {
	SLAVE = 0,
	MASTER
};

struct yt8xxx_priv {
	u8 chip_mode;
	u8 role;
	struct yt_ptp_private *ptp_priv;
};

enum yt8011_reg_space_type {
	YT8011_REG_SPACE_UTP,
	YT8011_REG_SPACE_SDS,
};

/* ext reg 0x8000 bit1:0 PTP_CLK_TYPE
 * 2'b00 Ordinary/boundary two-step clock;
 * 2'b01 Ordinary/boundary one-step clock;
 * 2'b10 Transparent two-step clock;
 * 2'b11 Transparent one-step clock;
 */
enum GPTP_CLK_MODE {
	OC_2_STEPS = 0,
	OC_1_STEPS,
	TC_2_STEPS,
	TC_1_STEPS
};

/* ext reg 0x8000 bit3:2 RTC_CLK_SEL
 * 2'b00: ADC clock, after rotator;
 * 2'b01: DAC clock;
 * 2'b10: ADC clock, before rotator;
 * 2'b11: SYNC_IN;
 */
enum CLK_SOURCE {
	ADC_CLK_AFTER_ROTATOR = 0,
	DAC_CLK,
	ADC_CLK_BEFORE_ROTATOR,
	SYNC_IN
};
#define VLAN_HLEN 4

#define SYNC                  0x0
#define DELAY_REQ             0x1
#define PDELAY_REQ            0x2
#define PDELAY_RESP           0x3
#define FOLLOW_UP             0x8
#define DELAY_RESP            0x9
#define PDELAY_RESP_FOLLOW_UP 0xA
#define ANNOUNCE              0xB
#define SIGNALING             0xC
#define MANAGEMENT            0xD

static int yt8011_select_page(struct phy_device *phydev, int page);
static int yt8011_restore_page(struct phy_device *phydev, int oldpage, int ret);
static long yt8011_ptp_do_aux_work(struct ptp_clock_info *clock_info);

#if (KERNEL_VERSION(5, 5, 0) > LINUX_VERSION_CODE)
static inline void phy_lock_mdio_bus(struct phy_device *phydev)
{
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	mutex_lock(&phydev->bus->mdio_lock);
#else
	mutex_lock(&phydev->mdio.bus->mdio_lock);
#endif
}

static inline void phy_unlock_mdio_bus(struct phy_device *phydev)
{
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	mutex_unlock(&phydev->bus->mdio_lock);
#else
	mutex_unlock(&phydev->mdio.bus->mdio_lock);
#endif
}
#endif

#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
static inline int __phy_read(struct phy_device *phydev, u32 regnum)
{
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	struct mii_bus *bus = phydev->bus;
	int addr = phydev->addr;
	return bus->read(bus, phydev->addr, regnum);
#else
	struct mii_bus *bus = phydev->mdio.bus;
	int addr = phydev->mdio.addr;
#endif
	return bus->read(bus, addr, regnum);
}

static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val)
{
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	struct mii_bus *bus = phydev->bus;
	int addr = phydev->addr;
#else
	struct mii_bus *bus = phydev->mdio.bus;
	int addr = phydev->mdio.addr;
#endif
	return bus->write(bus, addr, regnum, val);
}
#endif

static int __ytphy_read_ext(struct phy_device *phydev,
						    u32 regnum)
{
	int ret;

	ret = __phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
	if (ret < 0)
		return ret;

	return __phy_read(phydev, REG_DEBUG_DATA);
}

static int ytphy_read_ext(struct phy_device *phydev, u32 regnum)
{
	int ret;

	phy_lock_mdio_bus(phydev);
	ret = __phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
	if (ret < 0)
		goto err_handle;

	ret = __phy_read(phydev, REG_DEBUG_DATA);
	if (ret < 0)
		goto err_handle;

err_handle:
	phy_unlock_mdio_bus(phydev);

	return ret;
}

static int ytphy_write_ext(struct phy_device *phydev, u32 regnum, u16 val)
{
	int ret;

	phy_lock_mdio_bus(phydev);
	ret = __phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
	if (ret < 0)
		goto err_handle;

	ret = __phy_write(phydev, REG_DEBUG_DATA, val);
	if (ret < 0)
		goto err_handle;

err_handle:
	phy_unlock_mdio_bus(phydev);

	return ret;
}

static int __ytphy_write_ext(struct phy_device *phydev,
						     u32 regnum, u16 val)
{
	int ret;

	ret = __phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
	if (ret < 0)
		return ret;

	ret = __phy_write(phydev, REG_DEBUG_DATA, val);
	if (ret < 0)
		return ret;

	return 0;
}

static int ytphy_read_mmd(struct phy_device* phydev,
						  u16 device, u16 reg)
{
	int val;

	phy_lock_mdio_bus(phydev);

	__phy_write(phydev, REG_MII_MMD_CTRL, device);
	__phy_write(phydev, REG_MII_MMD_DATA, reg);
	__phy_write(phydev, REG_MII_MMD_CTRL, device | 0x4000);
	val = __phy_read(phydev, REG_MII_MMD_DATA);
	if (val < 0) {
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
		dev_err(&phydev->dev, "error read mmd device(%u) reg (%u)\n",
			device, reg);
#else
		dev_err(&phydev->mdio.dev,
			"error read mmd device(%u) reg (%u)\n", device, reg);
#endif

		goto err_handle;
	}

err_handle:
	phy_unlock_mdio_bus(phydev);

	return val;
}

__attribute__((unused)) static int ytphy_write_mmd(struct phy_device* phydev,
						   u16 device, u16 reg,
						   u16 value)
{
	int ret = 0;

	phy_lock_mdio_bus(phydev);

	__phy_write(phydev, REG_MII_MMD_CTRL, device);
	__phy_write(phydev, REG_MII_MMD_DATA, reg);
	__phy_write(phydev, REG_MII_MMD_CTRL, device | 0x4000);
	__phy_write(phydev, REG_MII_MMD_DATA, value);

	phy_unlock_mdio_bus(phydev);

	return ret;
}

__attribute__((unused)) static int __ytphy_read_mmd(struct phy_device* phydev,
						    u16 device, u16 reg)
{
	int val;

	__phy_write(phydev, REG_MII_MMD_CTRL, device);
	__phy_write(phydev, REG_MII_MMD_DATA, reg);
	__phy_write(phydev, REG_MII_MMD_CTRL, device | 0x4000);
	val = __phy_read(phydev, REG_MII_MMD_DATA);

	return val;
}

__attribute__((unused)) static int __ytphy_write_mmd(struct phy_device* phydev,
						     u16 device, u16 reg,
						     u16 value)
{
	__phy_write(phydev, REG_MII_MMD_CTRL, device);
	__phy_write(phydev, REG_MII_MMD_DATA, reg);
	__phy_write(phydev, REG_MII_MMD_CTRL, device | 0x4000);
	__phy_write(phydev, REG_MII_MMD_DATA, value);

	return 0;
}

static int __ytphy_soft_reset(struct phy_device *phydev)
{
	int ret = 0, val = 0;

	val = __phy_read(phydev, MII_BMCR);
	if (val < 0)
		return val;

	ret = __phy_write(phydev, MII_BMCR, val | BMCR_RESET);
	if (ret < 0)
		return ret;

	return ret;
}

struct yt_ptp_private {
	struct phy_device *phydev;
#if (KERNEL_VERSION(5, 5, 19) < LINUX_VERSION_CODE)
	struct mii_timestamper mii_ts;
#endif
	struct ptp_clock *clock;
	struct ptp_clock_info clock_info;
	struct mutex mutex;
	struct sk_buff_head tx_queue;
	int tx_type;	//ioctl()
	bool hwts_rx;	//ioctl()
	int layer;
	int version;
};

struct yt_ptp_skb_cb {
	unsigned long timeout;
	u16 seq_id;
	u8 msgtype;
};

struct yt_ptp_capture {
	ktime_t hwtstamp;
	u16 seq_id;
	u8 msgtype;
};

#if (KERNEL_VERSION(5, 5, 19) < LINUX_VERSION_CODE)
static struct yt_ptp_private *miits2ptppriv(struct mii_timestamper *mii_ts)
{
	return container_of(mii_ts, struct yt_ptp_private, mii_ts);
}
#endif

static struct yt_ptp_private *clkinfo2ptppriv(struct ptp_clock_info *clock_info)
{
	return container_of(clock_info, struct yt_ptp_private, clock_info);
}

static int yt8011_ptp_get_ts_paged(struct phy_device *phydev,
				   struct timespec64 *ts, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	/* ext reg 0x8049 rtc_real_time_i bit63:48(s_h) */
	ret = __ytphy_read_ext(phydev, 0x8049);
	if (ret < 0)
		goto err_restore_page;
	ts->tv_sec = (ret << 16);

	/* ext reg 0x804a rtc_real_time_i bit47:32(s_l) */
	ret = __ytphy_read_ext(phydev, 0x804a);
	if (ret < 0)
		goto err_restore_page;
	ts->tv_sec |= ret;

	/* ext reg 0x804b rtc_real_time_i bit31:16(ns_h) */
	ret = __ytphy_read_ext(phydev, 0x804b);
	if (ret < 0)
		goto err_restore_page;
	ts->tv_nsec = (ret << 16);

	/* ext reg 0x804c rtc_real_time_i bit15:0(ns_l) */
	ret = __ytphy_read_ext(phydev, 0x804c);
	if (ret < 0)
		goto err_restore_page;
	ts->tv_nsec |= ret;
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

static int yt8011_ptp_set_ts_paged(struct phy_device *phydev,
				     const struct timespec64 *ts, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	/* ext reg 0x8062(sec) RTC_PRELOAD_VAL bit63:48 */
	ret = __ytphy_write_ext(phydev, 0x8062, (ts->tv_sec >> 16) & 0xffff);
	if (ret < 0)
		goto err_restore_page;
	/* ext reg 0x8063(sec) RTC_PRELOAD_VAL bit47:32 */
	ret = __ytphy_write_ext(phydev, 0x8063, ts->tv_sec & 0xffff);
	if (ret < 0)
		goto err_restore_page;

	/* ext reg 0x8064(nsec) RTC_PRELOAD_VAL bit31:16 */
	ret = __ytphy_write_ext(phydev, 0x8064, (ts->tv_nsec >> 16) & 0xffff);
	if (ret < 0)
		goto err_restore_page;

	/* ext reg 0x8065(nsec) RTC_PRELOAD_VAL bit15:0 */
	ret = __ytphy_write_ext(phydev, 0x8065, ts->tv_nsec & 0xffff);
	if (ret < 0)
		goto err_restore_page;
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

static int yt8011_ptp_rtc_load_paged(struct phy_device *phydev, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	/* 
	 * YT8011 load RTC val, ext reg 0x8060 bit0 1'b1
	 * Setting it to 1 loads value 8061~8065 RTC_PRELOAD to RTC.
	 * This bit is self-clearing and always read back as 0.
	 */
	ret = __ytphy_read_ext(phydev, 0x8060);
	if (ret < 0)
		goto err_restore_page;

	ret = __ytphy_write_ext(phydev, 0x8060, ret | BIT(0));
	if (ret < 0)
		goto err_restore_page;
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

#if (KERNEL_VERSION(4, 20, 17) < LINUX_VERSION_CODE)
static int yt8011_ptp_gettimex(struct ptp_clock_info *clock_info,
			       struct timespec64 *ts,
			       struct ptp_system_timestamp *sts)
{
	struct yt_ptp_private *ptp_priv = clkinfo2ptppriv(clock_info);
	int err;

	mutex_lock(&ptp_priv->mutex);
	err = yt8011_ptp_get_ts_paged(ptp_priv->phydev, ts,
				      YT8011_REG_SPACE_UTP);
	mutex_unlock(&ptp_priv->mutex);

	return err < 0 ? err : 0;
}
#else
static int yt8011_ptp_gettime(struct ptp_clock_info *clock_info,
			      struct timespec64 *ts)
{
	struct yt_ptp_private *ptp_priv = clkinfo2ptppriv(clock_info);
	int err;

	mutex_lock(&ptp_priv->mutex);
	err = yt8011_ptp_get_ts_paged(ptp_priv->phydev, ts,
				      YT8011_REG_SPACE_UTP);
	mutex_unlock(&ptp_priv->mutex);

	return err < 0 ? err : 0;
}
#endif

static int yt8011_ptp_settime(struct ptp_clock_info *clock_info,
			      const struct timespec64 *ts)
{
	struct yt_ptp_private *ptp_priv = clkinfo2ptppriv(clock_info);
	int err;

	mutex_lock(&ptp_priv->mutex);
	err = yt8011_ptp_set_ts_paged(ptp_priv->phydev, ts,
				      YT8011_REG_SPACE_UTP);
	if (err < 0)
		goto out;

	err = yt8011_ptp_rtc_load_paged(ptp_priv->phydev,
					YT8011_REG_SPACE_UTP);
out:
	mutex_unlock(&ptp_priv->mutex);

	return err < 0 ? err : 0;
}

static int yt8011_ptp_adjtime_paged(struct phy_device *phydev,
				    struct timespec64* ts, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	/* ext reg 0x8045 OFFSET_SEC bit31:16 */
	ret = __ytphy_write_ext(phydev, 0x8045, (ts->tv_sec >> 16) & 0xffff);
	if (ret < 0)
		goto err_restore_page;

	/* ext reg 0x8046 OFFSET_SEC bit15:0 */
	ret = __ytphy_write_ext(phydev, 0x8046, ts->tv_sec & 0xffff);
	if (ret < 0)
		goto err_restore_page;

	/* ext reg 0x8042 OFFSET_NANO bit31:16 */
	ret = __ytphy_write_ext(phydev, 0x8042, (ts->tv_nsec >> 16) & 0xffff);
	if (ret < 0)
		goto err_restore_page;

	/* ext reg 0x8043 OFFSET_NANO bit15:0 */
	ret = __ytphy_write_ext(phydev, 0x8043, ts->tv_nsec & 0xffff);
	if (ret < 0)
		goto err_restore_page;

	/* ext reg 0x8047 EN_OFFSET bit0 
	 * 1'b1 adjust the RTC with the value OFFSET_SEC and OFFSET_NANO.
	 */
	ret = __ytphy_read_ext(phydev, 0x8047);
	if (ret < 0)
		goto err_restore_page;

	ret = __ytphy_write_ext(phydev, 0x8047, ret | BIT(0));
	if (ret < 0)
		goto err_restore_page;
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

static int yt8011_ptp_adjtime(struct ptp_clock_info *clock_info, s64 delta_ns)
{
	struct yt_ptp_private *ptp_priv = clkinfo2ptppriv(clock_info);
	struct phy_device *phydev = ptp_priv->phydev;
	struct timespec64 ts;
	int err;

	ts = ns_to_timespec64(delta_ns);
	mutex_lock(&ptp_priv->mutex);
	err = yt8011_ptp_adjtime_paged(phydev, &ts, YT8011_REG_SPACE_UTP);
	mutex_unlock(&ptp_priv->mutex);

	return err < 0 ? err : 0;
}

static int yt8011_ptp_adjfine_paged(struct phy_device *phydev,
				    unsigned long adj_step, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;
	/*
	 * ext reg 0x8040 RTC_STEP bit31:16
	 * ext reg 0x8041 RTC_STEP bit15:0
	 */
	ret = __ytphy_write_ext(phydev, 0x8040, (adj_step >> 16) & 0xffff);
	if (ret < 0)
		goto err_restore_page;

	ret = __ytphy_write_ext(phydev, 0x8041, adj_step & 0xffff);
	if (ret < 0)
		goto err_restore_page;
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

/* rtc clk 375MHz, rtc step = 1 000 000 000 / 375 000 000 = 2.66ns
 * fractional part(0.66 << 26 = 0x2AA AAAA), integer part(2 << 26 = 0x800 0000)
 * so, the frequency adjustment base is 0xAAA AAAA(0x2AA AAAA | 0x800 0000),
 * or 2.6666667 * (2^26) = (2.6666667 << 26)
 *
 * Frequency adjustment is
 * adj = {scaled_ppm * 0xAAAAAAA} / (10^6 * 2^16)
 * adj = {scaled_ppm * [2.6666667 * (2^26)]} / (10^6 * 2^16)
 * adj = {scaled_ppm * [2.6666667 * (2^26)]} / ((2 * 5)^6 * 2^16)
 * adj = {scaled_ppm * [2.6666667 * (2^26)]} / (5^6 * 2^22)
 * adj = {scaled_ppm * [2.6666667 * (2^4)]} / (5^6)
 * adj = {scaled_ppm * [2.6666667 * (2^4)]} / 15625
 * scaled_ppm: long(unit: ppm) and Q16.16 format
 * #define RTC_DEFAULT_CYCLE_RATE 0xAAAAAAA(2.6666667*(2^26))
 * double rate = (1000000 + scaled_ppm) / 10^6;
 * double rate = (1000000 + scaled_ppm) / 1000000;
 * double step = ((double)RTC_DEFAULT_CYCLE_RATE / 2^26) * rate;
 * double step = ((double)RTC_DEFAULT_CYCLE_RATE / 0x4000000) * rate;
 * unsigned long adj_step = (unsigned long)(step << 26 = step * 2^26);
 * unsigned long adj_step = (unsigned long)(step * 0x4000000);
 */
static int yt8011_ptp_adjfine(struct ptp_clock_info *clock_info,
			      long scaled_ppm)
{
#define RTC_DEFAULT_CYCLE_RATE 0xAAAAAAA
	struct yt_ptp_private *ptp_priv = clkinfo2ptppriv(clock_info);
	unsigned long adj_step;
	int neg_adj = 0;
	u32 diff;
	u64 adj;

	dbg_ptp("@jie.han %s, %s, %d scaled_ppm: %ld\n",
		__FILE__, __func__, __LINE__, scaled_ppm);

	if (scaled_ppm < 0) {
		neg_adj = 1;
		scaled_ppm = -scaled_ppm;
	}

	//adj = (scaled_ppm * 266667LL) / 100000LL;
	adj = (u64)scaled_ppm * 266667LL;
	adj = div64_u64(adj, 100000LL);
	adj <<= 4;
	diff = div_u64(adj, 15625);
	//diff = div64_u64(adj, 15625);
	adj_step = RTC_DEFAULT_CYCLE_RATE + (neg_adj ? -diff : diff);
	mutex_lock(&ptp_priv->mutex);
	yt8011_ptp_adjfine_paged(ptp_priv->phydev, adj_step,
				 YT8011_REG_SPACE_UTP);
	mutex_unlock(&ptp_priv->mutex);

	return 0;
}

#define YT_SKB_CB(skb)		((struct yt_ptp_skb_cb *)(skb)->cb)
static const struct ptp_clock_info yt8011_ptp_clock_info = {
	.owner		= THIS_MODULE,
	.name		= KBUILD_MODNAME,
	.max_adj	= 100000000,
#if (KERNEL_VERSION(4, 20, 17) < LINUX_VERSION_CODE)
	.gettimex64	= yt8011_ptp_gettimex,
#else
	.gettime64	= yt8011_ptp_gettime,
#endif
	.settime64	= yt8011_ptp_settime,
	.adjtime	= yt8011_ptp_adjtime,
	.adjfine	= yt8011_ptp_adjfine,
	.do_aux_work	= yt8011_ptp_do_aux_work,
};

static int yt_ptp_get_txtstamp_paged(struct phy_device *phydev,
				     struct yt_ptp_capture *capts, u8 page)
{
	int ret = 0, oldpage;
	uint32_t sec, nsec;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	ret = __ytphy_read_ext(phydev, 0x8020);
	if (ret < 0)
		goto err_restore_page;
	capts->seq_id = ret;

	ret = (__ytphy_read_ext(phydev, 0x802b) & 0xf000) >> 12;
	if (ret < 0)
		goto err_restore_page;
	capts->msgtype = ret;

	ret = __ytphy_read_ext(phydev, 0x8027);
	if (ret < 0)
		goto err_restore_page;
	sec = ret << 16;

	ret = __ytphy_read_ext(phydev, 0x8028);
	if (ret < 0)
		goto err_restore_page;
	sec |= ret;

	ret = __ytphy_read_ext(phydev, 0x8029);
	if (ret < 0)
		goto err_restore_page;
	nsec = ret << 16;

	ret = __ytphy_read_ext(phydev, 0x802a);
	if (ret < 0)
		goto err_restore_page;
	nsec |= ret;

	capts->hwtstamp = ktime_set(sec, nsec);
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret < 0 ? ret : 0);
}

static bool yt8011_ptp_get_txtstamp(struct yt_ptp_private *ptp_priv,
				    struct yt_ptp_capture *capts)
{
	struct phy_device *phydev = ptp_priv->phydev;
	int ret;

	//dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	mutex_lock(&ptp_priv->mutex);
	ret = yt_ptp_get_txtstamp_paged(phydev, capts, YT8011_REG_SPACE_UTP);
	mutex_unlock(&ptp_priv->mutex);
	dbg_ptp("@jie.han %s, %s, %d yt_ptp_get_txtstamp_paged() ret: %d, "
		"capts->seq_id: %d, capts->msgtype: %s\n",
		__FILE__, __func__, __LINE__, ret,
		capts->seq_id,
		capts->msgtype == SYNC ? "SYNC" :
		capts->msgtype == DELAY_REQ ? "DELAY_REQ" :
		capts->msgtype == PDELAY_REQ ? "PDELAY_REQ" :
		capts->msgtype == PDELAY_RESP ? "PDELAY_RESP" :
		capts->msgtype == FOLLOW_UP ? "FOLLOW_UP" :
		capts->msgtype == DELAY_RESP ? "DELAY_RESP" :
		capts->msgtype == PDELAY_RESP_FOLLOW_UP ? "PDELAY_RESP_FOLLOW_UP" :
		capts->msgtype == ANNOUNCE ? "ANNOUNCE" :
		capts->msgtype == SIGNALING ? "SIGNALING" :
		capts->msgtype == MANAGEMENT ? "MANAGEMENT" : "other");
	return (ret < 0 ? false : true);
}

static bool yt8011_ptp_match_txtstamp(struct yt_ptp_private *ptp_priv,
				      struct yt_ptp_capture *capts)
{
	//struct skb_shared_hwtstamps hwts;
	struct skb_shared_hwtstamps *shhwtstamps;
	//struct sk_buff *skb, *ts_skb;
	unsigned long now = jiffies;
	struct sk_buff *skb, *skb_tmp;
	bool matched = false;
	unsigned long flags;
	//bool first = false;
	u8 msgtype;
	u16 seqid;

	//dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	//ts_skb = NULL;
	spin_lock_irqsave(&ptp_priv->tx_queue.lock, flags);
	skb_queue_walk_safe(&ptp_priv->tx_queue, skb, skb_tmp) {
		dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_flags: %#lx\n",
			__FILE__, __func__, __LINE__, skb->sk->sk_flags);
		//dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_refcnt: %d\n",
			//__FILE__, __func__, __LINE__, atomic_read(&skb->sk->sk_refcnt));	//compile err
			//__FILE__, __func__, __LINE__, refcount_read(&skb->sk->sk_refcnt));//compile err
			//__FILE__, __func__, __LINE__, skb->sk->sk_refcnt.refs.counter);
		dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_refcnt: %d\n",
			__FILE__, __func__, __LINE__, skb->sk->sk_refcnt.refs.counter);
		if (time_after(now, YT_SKB_CB(skb)->timeout)) {
			dbg_ptp("@jie.han %s, %s, %d time_after(skb) timeout, then free it.\n",
				__FILE__, __func__, __LINE__);
			__skb_unlink(skb, &ptp_priv->tx_queue);
			if (skb->sk)
				sock_put(skb->sk);
			kfree_skb(skb); 		
			continue;
		}

		seqid = YT_SKB_CB(skb)->seq_id;
		msgtype = YT_SKB_CB(skb)->msgtype;
		if (seqid == capts->seq_id && msgtype == capts->msgtype) {
			__skb_unlink(skb, &ptp_priv->tx_queue);
			dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_flags: %#lx\n",
				__FILE__, __func__, __LINE__, skb->sk->sk_flags);

			shhwtstamps = skb_hwtstamps(skb);
			memset(shhwtstamps, 0, sizeof(*shhwtstamps));
			shhwtstamps->hwtstamp = capts->hwtstamp;

			//skb->tstamp = ktime_to_ns(capts->hwtstamp);
			skb->tstamp = ktime_get_real();
			skb->ip_summed = CHECKSUM_UNNECESSARY;
			
			dbg_ptp("@jie.han %s, %s, %d matched, seqid: %d, msgtype: %s\n",
				__FILE__, __func__, __LINE__,
				seqid,
				msgtype == SYNC ? "SYNC" :
				msgtype == DELAY_REQ ? "DELAY_REQ" :
				msgtype == PDELAY_REQ ? "PDELAY_REQ" :
				msgtype == PDELAY_RESP ? "PDELAY_RESP" :
				msgtype == FOLLOW_UP ? "FOLLOW_UP" :
				msgtype == DELAY_RESP ? "DELAY_RESP" :
				msgtype == PDELAY_RESP_FOLLOW_UP ? "PDELAY_RESP_FOLLOW_UP" :
				msgtype == ANNOUNCE ? "ANNOUNCE" :
				msgtype == SIGNALING ? "SIGNALING" :
				msgtype == MANAGEMENT ? "MANAGEMENT" : "other");

			if (skb->sk) {
				//__skb_complete_tx_timestamp(skb, skb->sk,
				//			SCM_TSTAMP_SND, false);
				//sock_put(skb->sk);
				dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_flags: %#lx\n",
					__FILE__, __func__, __LINE__, skb->sk->sk_flags);
				memset(YT_SKB_CB(skb), 0x0, sizeof(struct yt_ptp_skb_cb));
				skb_complete_tx_timestamp(skb, shhwtstamps);
			} else
				kfree_skb(skb);

			matched = true;
			break;
		}
	}

	spin_unlock_irqrestore(&ptp_priv->tx_queue.lock, flags);

	return matched;
}

void yt8011_ptp_purge_tx_queue(struct yt_ptp_private *ptp_priv)
{
	struct sk_buff *skb, *tmp;
	unsigned long flags;

	spin_lock_irqsave(&ptp_priv->tx_queue.lock, flags);

	skb_queue_walk_safe(&ptp_priv->tx_queue, skb, tmp) {
		__skb_unlink(skb, &ptp_priv->tx_queue);

		if (skb->sk)
			sock_put(skb->sk);

		kfree_skb(skb);
	}

	spin_unlock_irqrestore(&ptp_priv->tx_queue.lock, flags);
}

static long yt8011_ptp_do_aux_work(struct ptp_clock_info *clock_info)
{
	struct yt_ptp_private *ptp_priv = clkinfo2ptppriv(clock_info);
	struct yt_ptp_capture capts;
	bool reschedule = false;
	int limit = 8;
	
	memset(&capts, 0x0, sizeof(capts));
	//dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	/* ref to bcm and nxp in kernel v6.9 */
	while (!skb_queue_empty_lockless(&ptp_priv->tx_queue) && limit--) {
		if (!yt8011_ptp_get_txtstamp(ptp_priv, &capts)) {
			reschedule = true;
			break;
		}
		if (!yt8011_ptp_match_txtstamp(ptp_priv, &capts)) {		
			pr_warn("@jie.han %s, %s, %d "
				"failed to match TX timestamp, msgtype = 0x%x, seqid = %d\n",
				__FILE__, __func__, __LINE__, capts.msgtype, capts.seq_id);
			//skb_queue_purge(&ptp_priv->tx_queue);
			yt8011_ptp_purge_tx_queue(ptp_priv);
			reschedule = true;
			break;
		}
	}

	/* delay of the next auxiliary work scheduling time (>=0) or
	 * negative value in case further scheduling is not required.
	 */
	dbg_ptp("@jie.han %s, %s, %d reschedule: %s\n",
		__FILE__, __func__, __LINE__, reschedule == true ? "true" : "false");
	return reschedule ? 1 : -1;
}

static int yt8011_ptp_get_rxtstamp_paged(struct phy_device *phydev,
					 u8 eventtype, u16 seqid, 
					 u32 *sec, u32 *nsec,
					 u8 page)
{
	int ret = 0, oldpage;
	uint16_t id;
	int type;
	int idx;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	for (idx = 0; idx < 4; idx++) {
		if (idx == 0) {
			ret = __ytphy_read_ext(phydev, 0x8010);
			if (ret < 0)
				goto err_restore_page;
			id = ret;
			ret = __ytphy_read_ext(phydev, 0x801b);
			if (ret < 0)
				goto err_restore_page;
			type = (ret & 0xf000) >> 12;
			if (id == seqid && type == eventtype) {
				ret = __ytphy_read_ext(phydev, 0x8017);
				if (ret < 0)
					goto err_restore_page;
				*sec = ret << 16;

				ret = __ytphy_read_ext(phydev, 0x8018);
				if (ret < 0)
					goto err_restore_page;
				*sec |= ret;

				ret = __ytphy_read_ext(phydev, 0x8019);
				if (ret < 0)
					goto err_restore_page;
				*nsec = ret << 16;

				ret = __ytphy_read_ext(phydev, 0x801a);
				if (ret < 0)
					goto err_restore_page;
				*nsec |= ret;
				break;
			}
		} else if (idx == 1) {
			ret = __ytphy_read_ext(phydev, 0x8100);
			if (ret < 0)
				goto err_restore_page;
			id = ret;
			ret = __ytphy_read_ext(phydev, 0x810b);
			if (ret < 0)
				goto err_restore_page;
			type = (ret & 0xf000) >> 12;
			if (id == seqid && type == eventtype) {
				ret = __ytphy_read_ext(phydev, 0x8107);
				if (ret < 0)
					goto err_restore_page;
				*sec = ret << 16;

				ret = __ytphy_read_ext(phydev, 0x8108);
				if (ret < 0)
					goto err_restore_page;
				*sec |= ret;

				ret = __ytphy_read_ext(phydev, 0x8109);
				if (ret < 0)
					goto err_restore_page;
				*nsec = ret << 16;

				ret= __ytphy_read_ext(phydev, 0x810a);
				if (ret < 0)
					goto err_restore_page;
				*nsec |= ret;
				break;
			}
		} else if (idx == 2) {
			ret = __ytphy_read_ext(phydev, 0x8110);
			if (ret < 0)
				goto err_restore_page;
			ret = __ytphy_read_ext(phydev, 0x811b);
			if (ret < 0)
				goto err_restore_page;
			type = (ret & 0xf000) >> 12;
			if (id == seqid && type == eventtype) {
				ret = __ytphy_read_ext(phydev, 0x8117);
				if (ret < 0)
					goto err_restore_page;
				*sec = ret << 16;

				ret = __ytphy_read_ext(phydev, 0x8118);
				if (ret < 0)
					goto err_restore_page;
				*sec |= ret;

				ret = __ytphy_read_ext(phydev, 0x8119);
				if (ret < 0)
					goto err_restore_page;
				*nsec = ret << 16;

				ret = __ytphy_read_ext(phydev, 0x811a);
				if (ret < 0)
					goto err_restore_page;
				*nsec |= ret;
				break;
			}
		} else if (idx == 3) {
			ret = __ytphy_read_ext(phydev, 0x8120);
			if (ret < 0)
				goto err_restore_page;
			ret = __ytphy_read_ext(phydev, 0x812b);
			if (ret < 0)
				goto err_restore_page;
			type = (ret & 0xf000) >> 12;
			if (id == seqid && type == eventtype) {
				ret = __ytphy_read_ext(phydev, 0x8127);
				if (ret < 0)
					goto err_restore_page;
				*sec = ret << 16;

				ret = __ytphy_read_ext(phydev, 0x8128);
				if (ret < 0)
					goto err_restore_page;
				*sec |= ret;

				ret = __ytphy_read_ext(phydev, 0x8129);
				if (ret < 0)
					goto err_restore_page;
				*nsec = ret << 16;

				ret = __ytphy_read_ext(phydev, 0x812a);
				if (ret < 0)
					goto err_restore_page;
				*nsec |= ret;
				break;
			}
		}
	}
 
	dbg_ptp("@jie.han %s, %s, %d idx: %d\n",
		__FILE__, __func__, __LINE__, idx);
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

#if (KERNEL_VERSION(5, 5, 19) < LINUX_VERSION_CODE)
static bool yt8011_ptp_mii_rxtstamp(struct mii_timestamper *mii_ts,
				    struct sk_buff *skb, int type)
{
	struct yt_ptp_private *ptp_priv = miits2ptppriv(mii_ts);
	struct phy_device *phydev = ptp_priv->phydev;
	struct skb_shared_hwtstamps *hwts;
	struct ptp_header *header;
	u16 sequence_id;
	u32 sec, nsec;
	u8 msg_type;
	int ret;

	dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	if (!ptp_priv->hwts_rx)
		return false;

	header = ptp_parse_header(skb, type);
	if (!header)
		return false;
	msg_type = ptp_get_msgtype(header, type);
	sequence_id = header->sequence_id;

	ret = yt8011_ptp_get_rxtstamp_paged(phydev, msg_type,
					    sequence_id, &sec, &nsec,
					    YT8011_REG_SPACE_UTP);
	if (ret > 0) {
		//get the rx timestamp and assigned skb's hwts->hwtstamp
		hwts = skb_hwtstamps(skb);
		hwts->hwtstamp = ktime_set(sec, nsec);
		netif_rx(skb);
		return true;
	} else
		return false;
}

static void yt8011_ptp_mii_txtstamp(struct mii_timestamper *mii_ts,
				    struct sk_buff *skb, int type)
{
	struct yt_ptp_private *ptp_priv = miits2ptppriv(mii_ts);
	struct ptp_header *hdr;
	int msgtype;

	dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	hdr = ptp_parse_header(skb, type);
	if (!hdr)
		goto out;
	msgtype = ptp_get_msgtype(hdr, type);

	dbg_ptp("@jie.han %s, %s, %d ptp_priv->tx_type: %d\n",
		__FILE__, __func__, __LINE__, ptp_priv->tx_type);
	switch (ptp_priv->tx_type) {
	case HWTSTAMP_TX_ONESTEP_P2P:
	case HWTSTAMP_TX_ONESTEP_SYNC:
	case HWTSTAMP_TX_ON:
		YT_SKB_CB(skb)->timeout = jiffies + SKB_TIMESTAMP_TIMEOUT;
		YT_SKB_CB(skb)->seq_id = be16_to_cpu(hdr->sequence_id);
		YT_SKB_CB(skb)->msgtype = msgtype;
		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
		skb_queue_tail(&ptp_priv->tx_queue, skb);
		ptp_schedule_worker(ptp_priv->clock, 0);
		return;
	default:
		break;
	}

out:
	kfree_skb(skb);
}

static int yt8011_ptp_mii_hwtstamp(struct mii_timestamper *mii_ts,
				   struct kernel_hwtstamp_config *cfg,
				   struct netlink_ext_ack *extack)
{
	struct yt_ptp_private *ptp_priv = miits2ptppriv(mii_ts);
	struct yt8xxx_priv *priv;
	u16 cfg0 = 0, cfg1 = 0;

	dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	priv = container_of(ptp_priv, struct yt8xxx_priv, ptp_priv);
	switch (cfg.rx_filter) {
	case HWTSTAMP_FILTER_NONE:
	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
		ptp_priv->hwts_rx = 0;
		ptp_priv->layer = 0;
		ptp_priv->version = 0;
		break;
	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
		ptp_priv->hwts_rx = 1;
		ptp_priv->layer = PTP_CLASS_L4;
		ptp_priv->version = PTP_CLASS_V2;
		break;
	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
		ptp_priv->hwts_rx = 1;
		ptp_priv->layer = PTP_CLASS_L2;
		ptp_priv->version = PTP_CLASS_V2;
		break;
	case HWTSTAMP_FILTER_PTP_V2_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
		ptp_priv->hwts_rx = 1;
		ptp_priv->layer = PTP_CLASS_L4 | PTP_CLASS_L2;
		ptp_priv->version = PTP_CLASS_V2;
		break;
	default:
		return -ERANGE;
	}
	ptp_priv->tx_type = cfg->tx_type;

	cfg0 |= OC_2_STEPS;

	if (priv->role == MASTER)
		cfg0 |= (DAC_CLK << 2);
	else
		cfg0 |= (ADC_CLK_AFTER_ROTATOR << 2);

	/* ext reg 0x8000 bit4 BP_1588
	 * 1'b0 = PTP timestamp engine normal operation.
	 * 1'b1 = Bypass IEEE1588v2 related functions.	  
	 */
	cfg0 &= ~BIT(4);
	
	/* ext reg 0x8000 bit7 EN_GATE_1588
	 * 1'b0 = Disable gating 1588 clock domain.
	 * 1'b1 = Enable gating 1588 clock domain.
	 */
	cfg0 &= ~BIT(7);

	/* ext reg 0x8001 bit4
	 * 1'b1: PTP mode  1'b0:gPTP mode(802.1AS)
	 */
	if (ptp_priv->layer & PTP_CLASS_L4)
		cfg1 |= BIT(4);
	else
		cfg1 &= ~BIT(4);
	mutex_lock(&ptp_priv->mutex);
	yt8011_ptp_init_paged(ptp_priv->phydev, cfg0, cfg1,
			      YT8011_REG_SPACE_UTP);

	mutex_unlock(&ptp_priv->mutex);

	/* purge existing data */
	skb_queue_purge(&priv->tx_queue);

	return 0;
}

static int yt8011_ptp_mii_ts_info(struct mii_timestamper *mii_ts,
				  struct ethtool_ts_info *ts_info)
{
	struct yt_ptp_private *ptp_priv = miits2ptppriv(mii_ts);

	dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	ts_info->phc_index = ptp_clock_index(ptp_priv->clock);
	ts_info->so_timestamping =	//software and hardware ts support
		SOF_TIMESTAMPING_TX_SOFTWARE |
		SOF_TIMESTAMPING_RX_SOFTWARE |
		SOF_TIMESTAMPING_SOFTWARE |
		SOF_TIMESTAMPING_TX_HARDWARE |
		SOF_TIMESTAMPING_RX_HARDWARE |
		SOF_TIMESTAMPING_RAW_HARDWARE;

	//v5.15 support HWTSTAMP_TX_ONESTEP_P2P
	ts_info->tx_types =			//hardware ts support only
		BIT(HWTSTAMP_TX_ON) |
		BIT(HWTSTAMP_TX_OFF) |
		//BIT(HWTSTAMP_TX_ONESTEP_SYNC) |
		BIT(HWTSTAMP_TX_ONESTEP_P2P);
	ts_info->rx_filters =		//hardware ts support only
		BIT(HWTSTAMP_FILTER_NONE) |
		BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);

	return 0;
}
#endif

time64_t read_rtc_time_sec(void) {
	struct rtc_device *rtc;
	struct rtc_time tm;
	int ret;
	time64_t seconds = 0;
	//u64 nanoseconds;

	// 1. �� RTC �豸(�����豸��Ϊ "rtc0")
	//https://elixir.bootlin.com/linux/v3.8.13/A/ident/rtc_class_open
	//https://elixir.bootlin.com/linux/v6.15-rc5/A/ident/rtc_class_open
	rtc = rtc_class_open("rtc0");
	if (IS_ERR(rtc)) {
		pr_err("Failed to open RTC device");
		return seconds;
	}

	// 2. ��ȡʱ�䵽 tm �ṹ��
	//https://elixir.bootlin.com/linux/v3.8.13/A/ident/rtc_read_time
	//https://elixir.bootlin.com/linux/v6.15-rc5/A/ident/rtc_read_time
	ret = rtc_read_time(rtc, &tm);
	if (ret) {
		pr_err("Failed to read RTC time");
		goto out;
	}

	// 3. �� rtc_time ת��Ϊ Unix ʱ���(��)
	//https://elixir.bootlin.com/linux/v3.19/A/ident/rtc_tm_to_time64
	//https://elixir.bootlin.com/linux/v6.15-rc5/A/ident/rtc_tm_to_time64
	seconds = rtc_tm_to_time64(&tm);

	// 4. ת��Ϊ����
	//nanoseconds = seconds * NSEC_PER_SEC;

	//pr_info("RTC Time: %lld.%09d seconds since 1970-01-01 00:00:00 UTC",
	//        (long long)seconds, (int)(nanoseconds % NSEC_PER_SEC));

out:
	rtc_class_close(rtc); // �ر��豸
	return seconds;
}

static int yt8011_ptp_init_paged(struct phy_device *phydev,
				 u16 cfg0, u16 cfg1, u8 page)
{
	int ret = 0, oldpage;
	time64_t seconds;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	ret = __ytphy_write_ext(phydev, 0x8000, cfg0);
	if (ret < 0)
		goto err_restore_page;

	ret = __ytphy_write_ext(phydev, 0x8001, cfg1);
	if (ret < 0)
		goto err_restore_page;

	/* rtc step cfg
	 * rtc clk f = 375MHz, T = 2.6666667ns
	 * rtc step = T << 26 = 0xaaa aaaa
	 * ext reg 0x8040 RTC_STEP
	 * bit31:16 MSB 16bits of part of the RTC step.
	 * ext reg 0x8041 RTC_STEP
	 * bit15:0 LSB 16bits of part of the RTC step.
	 */
	ret = __ytphy_write_ext(phydev, 0x8040, 0x0aaa);
	if (ret < 0)
		goto err_restore_page;

	ret = __ytphy_write_ext(phydev, 0x8041, 0xaaaa);
	if (ret < 0)
		goto err_restore_page;

	/* rtc cfg
	 * eg, 2023-01-01 00h00m00 s -> 1672531200 s -> 0x63b0 cd00
	 * write ext reg 0x8061(sec) RTC_PRELOAD_VAL bit79:64
	 * write ext reg 0x8062(sec) RTC_PRELOAD_VAL bit63:48
	 * write ext reg 0x8063(sec) RTC_PRELOAD_VAL bit47:32
	 * write ext reg 0x8064(nsec) RTC_PRELOAD_VAL bit31:16
	 * write ext reg 0x8065(nsec) RTC_PRELOAD_VAL bit15:0
	 */
	seconds = read_rtc_time_sec();
	/* s_h */
	ret = __ytphy_write_ext(phydev, 0x8061, 0x0);
	if (ret < 0)
		goto err_restore_page;
	/* s_m */
	//ret = __ytphy_write_ext(phydev, 0x8062, 0x63b0);
	ret = __ytphy_write_ext(phydev, 0x8062, (seconds >> 16) & 0xffff);
	if (ret < 0)
		goto err_restore_page;
	/* s_l */
	//ret = __ytphy_write_ext(phydev, 0x8063, 0xcd00);
	ret = __ytphy_write_ext(phydev, 0x8063, seconds & 0xffff);
	if (ret < 0)
		goto err_restore_page;
	/* ns_h */
	ret = __ytphy_write_ext(phydev, 0x8064, 0x0);
	if (ret < 0)
		goto err_restore_page;
	/* ns_l */
	ret = __ytphy_write_ext(phydev, 0x8065, 0x0);
	if (ret < 0)
		goto err_restore_page;

	/* load rtc
	 * ext reg 0x8060 bit0 LOAD_RTC
	 * 1'b1 loads value 0x8061~0x8065 RTC_PRELOAD to RTC.
	 * This bit is self-clearing and always read back as 0.
	 */
	ret = __ytphy_read_ext(phydev, 0x8060);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x8060, ret | BIT(0));
	if (ret < 0)
		goto err_restore_page;
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

struct yt_ptp_private *yt8011_ptp_priv(struct phy_device *phydev)
{
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	struct device *dev = &phydev->dev;
#else
	struct device *dev = &phydev->mdio.dev;
#endif
	struct yt_ptp_private *ptp_priv;
	struct ptp_clock *clock;

	ptp_priv = devm_kzalloc(dev, sizeof(*ptp_priv), GFP_KERNEL);
	if (!ptp_priv)
		return ERR_PTR(-ENOMEM);
		//return -ENOMEM;

	ptp_priv->clock_info = yt8011_ptp_clock_info;

	clock = ptp_clock_register(&ptp_priv->clock_info, dev);
	if (IS_ERR(clock))
		return ERR_CAST(clock);
	ptp_priv->clock = clock;

	ptp_priv->phydev = phydev;
	mutex_init(&ptp_priv->mutex);
	skb_queue_head_init(&ptp_priv->tx_queue);
#if (KERNEL_VERSION(5, 6, 0) > LINUX_VERSION_CODE)
#else
	ptp_priv->mii_ts.rxtstamp = yt8011_ptp_mii_rxtstamp;
	ptp_priv->mii_ts.txtstamp = yt8011_ptp_mii_txtstamp;
	ptp_priv->mii_ts.hwtstamp = yt8011_ptp_mii_hwtstamp;
	ptp_priv->mii_ts.ts_info = yt8011_ptp_mii_ts_info;
	ptp_priv->phydev->mii_ts = &ptp_priv->mii_ts;
#endif	
	return ptp_priv;
}

static int yt8011_probe(struct phy_device *phydev)
{
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	struct device *dev = &phydev->dev;
#else
	struct device *dev = &phydev->mdio.dev;
#endif
	struct yt8xxx_priv *priv;
	int chip_config;
	u16 role;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		//return ERR_PTR(-ENOMEM);
		return -ENOMEM;

	phydev->priv = priv;

	/* ext reg 0x9030 bit0 
	 * 0 = chip works in RGMII mode; 1 = chip works in SGMII mode 
	 */
	chip_config = ytphy_read_ext(phydev, 0x9030);
	priv->chip_mode = chip_config & 0x1;

	role = ytphy_read_mmd(phydev, 0x1, 0x834);
	
	priv->role = role & BIT(14) ? MASTER : SLAVE;
	priv->ptp_priv = yt8011_ptp_priv(phydev);
	if (IS_ERR(priv->ptp_priv))
		return PTR_ERR(priv->ptp_priv);
	return 0;
}

static int yt8011_soft_reset_paged(struct phy_device *phydev, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage >= 0)
		ret = __ytphy_soft_reset(phydev);

	return yt8011_restore_page(phydev, oldpage, ret);
}

static int yt8011_soft_reset(struct phy_device *phydev)
{
	struct yt8xxx_priv *priv = phydev->priv;

	/* utp */
	yt8011_soft_reset_paged(phydev, YT8011_REG_SPACE_UTP);

	if (priv->chip_mode) {	/* sgmii */
		yt8011_soft_reset_paged(phydev, YT8011_REG_SPACE_SDS);
	}

	return 0;
}

static int yt8011_config_aneg(struct phy_device *phydev)
{
	return 0;
}

#if (KERNEL_VERSION(3, 14, 79) < LINUX_VERSION_CODE)
static int yt8011_aneg_done(struct phy_device *phydev)
{
	int link_utp = 0;

	/* UTP */
	ytphy_write_ext(phydev, 0x9000, 0);
	link_utp = !!(phy_read(phydev, REG_PHY_SPEC_STATUS) &
			(BIT(YTXXXX_LINK_STATUS_BIT)));

#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	netdev_info(phydev->attached_dev, "%s, phy addr: %d, link_utp: %d\n",
		    __func__, phydev->addr, link_utp);
#else
	netdev_info(phydev->attached_dev, "%s, phy addr: %d, link_utp: %d\n",
		    __func__, phydev->mdio.addr, link_utp);
#endif

	return !!(link_utp);
}
#endif

static int yt8011_config_paged(struct phy_device *phydev, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	ret = __ytphy_write_ext(phydev, 0x1008, 0x2119);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x1092, 0x712);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x90bc, 0x7676);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x90b9, 0x620b);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x2001, 0x6418);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x1019, 0x3712);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x101a, 0x3713);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x2005, 0x810);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x2015, 0x1012);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x2013, 0xff06);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x3017, 0x4);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x3027, 0xffe8);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x3026, 0x1b58);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x301e, 0xb40);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x3019, 0xffd4);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x3014, 0x1115);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x301a, 0x7800);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x1000, 0x28);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x1053, 0xf);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x105e, 0xa46c);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x1088, 0x2b);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x1088, 0x2b);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x1088, 0xb);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x3008, 0x141);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x3009, 0x1918);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x9095, 0x1a1a);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x9096, 0x1a10);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x9097, 0x101a);
	if (ret < 0)
		goto err_restore_page;
	ret = __ytphy_write_ext(phydev, 0x9098, 0x01ff);
	if (ret < 0)
		goto err_restore_page;
err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

__attribute__((unused))
static int yt8011_config_rgmii_dvddio_3v3_paged(struct phy_device *phydev, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	if (page == YT8011_REG_SPACE_SDS) {
		ret = __ytphy_write_ext(phydev, 0x0062, 0x0000);
		if (ret < 0)
			goto err_restore_page;
	} else if (page == YT8011_REG_SPACE_UTP) {
		ret = __ytphy_write_ext(phydev, 0x9031, 0xb200);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x903b, 0x0040);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x903e, 0x3b3b);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x903c, 0xf);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x903d, 0x1000);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9038, 0x0000);
		if (ret < 0)
			goto err_restore_page;
	}

err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

__attribute__((unused))
static int yt8011_config_rgmii_dvddio_2v5_paged(struct phy_device *phydev, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	if (page == YT8011_REG_SPACE_SDS) {
		ret = __ytphy_write_ext(phydev, 0x0062, 0x0000);
		if (ret < 0)
			goto err_restore_page;
	} else if (page == YT8011_REG_SPACE_UTP) {
		ret = __ytphy_write_ext(phydev, 0x9031, 0xb200);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9111, 0x5);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9114, 0x3939);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9112, 0xf);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9110, 0x0);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9113, 0x10);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x903d, 0x2);
		if (ret < 0)
			goto err_restore_page;
	}

err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

__attribute__((unused))
static int yt8011_config_rgmii_dvddio_1v8_paged(struct phy_device *phydev, int page)
{
	int ret = 0, oldpage;

	oldpage = yt8011_select_page(phydev, page);
	if (oldpage < 0)
		goto err_restore_page;

	if (page == YT8011_REG_SPACE_SDS) {
		ret = __ytphy_write_ext(phydev, 0x0062, 0x0000);
		if (ret < 0)
			goto err_restore_page;
	} else if (page == YT8011_REG_SPACE_UTP) {
		ret = __ytphy_write_ext(phydev, 0x9031, 0xb200);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9116, 0x6);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9119, 0x3939);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9117, 0xf);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9115, 0x0);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x9118, 0x20);
		if (ret < 0)
			goto err_restore_page;
		ret = __ytphy_write_ext(phydev, 0x903d, 0x3);
		if (ret < 0)
			goto err_restore_page;
	}

err_restore_page:
	return yt8011_restore_page(phydev, oldpage, ret);
}

/* #define YT801X_RGMII_DVDDIO_3V3 */
/* #define YT801X_RGMII_DVDDIO_2V5 */
/* #define YT801X_RGMII_DVDDIO_1V8 */
static int yt8011_config_init(struct phy_device *phydev)
{
	struct yt8xxx_priv *priv = phydev->priv;
	int ret;

	phydev->autoneg = AUTONEG_DISABLE;

	ret = yt8011_config_paged(phydev, YT8011_REG_SPACE_UTP);
	if (ret < 0)
		return ret;
	if (!(priv->chip_mode)) {	/* rgmii config */
#if defined (YT801X_RGMII_DVDDIO_3V3)
		ret = yt8011_config_rgmii_dvddio_3v3_paged(phydev,
							   YT8011_REG_SPACE_SDS);
		if (ret < 0)
			return ret;
		ret = yt8011_config_rgmii_dvddio_3v3_paged(phydev,
							   YT8011_REG_SPACE_UTP);
		if (ret < 0)
			return ret;
#elif defined (YT801X_RGMII_DVDDIO_2V5)
		ret = yt8011_config_rgmii_dvddio_2v5_paged(phydev,
							   YT8011_REG_SPACE_SDS);
		if (ret < 0)
			return ret;
		ret = yt8011_config_rgmii_dvddio_2v5_paged(phydev,
							   YT8011_REG_SPACE_UTP);
		if (ret < 0)
			return ret;
#elif defined (YT801X_RGMII_DVDDIO_1V8)
		ret = yt8011_config_rgmii_dvddio_1v8_paged(phydev,
							   YT8011_REG_SPACE_SDS);
		if (ret < 0)
			return ret;
		ret = yt8011_config_rgmii_dvddio_1v8_paged(phydev,
							   YT8011_REG_SPACE_UTP);
		if (ret < 0)
			return ret;
#endif
	}

	if (phydev->drv->txtstamp)
		dbg_ptp("@jie.han %s, %s, %d phydev->drv->txtstamp registed.\n",
		__FILE__, __func__, __LINE__);
	else
		dbg_ptp("@jie.han %s, %s, %d phydev->drv->txtstamp not registed.\n",
		__FILE__, __func__, __LINE__);
	if (phydev->drv->rxtstamp)
		dbg_ptp("@jie.han %s, %s, %d phydev->drv->rxtstamp registed.\n",
		__FILE__, __func__, __LINE__);
	else
		dbg_ptp("@jie.han %s, %s, %d phydev->drv->rxtstamp not registed.\n",
		__FILE__, __func__, __LINE__);

	yt8011_soft_reset(phydev);

#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
	netdev_info(phydev->attached_dev, "%s done, phy addr: %d\n",
		    __func__, phydev->addr);
#else
	netdev_info(phydev->attached_dev, "%s done, phy addr: %d\n",
		    __func__, phydev->mdio.addr);
#endif

	return 0;
}

static int ytxxxx_automotive_adjust_status(struct phy_device *phydev, int val)
{
	int speed_mode;
#if (KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE)
	int speed = -1;
#else
	int speed = SPEED_UNKNOWN;
#endif

	speed_mode = (val & YTXXXX_SPEED_MODE) >> YTXXXX_SPEED_MODE_BIT;
	switch (speed_mode) {
	case 1:
		speed = SPEED_100;
		break;
	case 2:
		speed = SPEED_1000;
		break;
	default:
#if (KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE)
		speed = -1;
#else
		speed = SPEED_UNKNOWN;
#endif
		break;
	}

	phydev->speed = speed;
	phydev->duplex = DUPLEX_FULL;

	return 0;
}

static int yt8011_read_status(struct phy_device *phydev)
{
	int ret;
	int val;
	int link;
	int link_utp = 0;

	/* UTP */
	ret = ytphy_write_ext(phydev, 0x9000, 0x0);
	if (ret < 0)
		return ret;

	val = phy_read(phydev, REG_PHY_SPEC_STATUS);
	if (val < 0)
		return val;

	link = val & (BIT(YTXXXX_LINK_STATUS_BIT));
	if (link) {
		link_utp = 1;
		ytxxxx_automotive_adjust_status(phydev, val);
	} else {
		link_utp = 0;
	}

	if (link_utp) {
		if (phydev->link == 0)
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
			netdev_info(phydev->attached_dev,
				    "%s, phy addr: %d, link up, media: UTP, mii reg 0x11 = 0x%x\n",
				    __func__, phydev->addr, (unsigned int)val);
#else
			netdev_info(phydev->attached_dev,
				    "%s, phy addr: %d, link up, media: UTP, mii reg 0x11 = 0x%x\n",
				    __func__, phydev->mdio.addr,
				    (unsigned int)val);
#endif
		phydev->link = 1;
	} else {
		if (phydev->link == 1)
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
			netdev_info(phydev->attached_dev,
				    "%s, phy addr: %d, link down\n",
				    __func__, phydev->addr);
#else
			netdev_info(phydev->attached_dev,
				    "%s, phy addr: %d, link down\n",
				    __func__, phydev->mdio.addr);
#endif
		phydev->link = 0;
	}

	if (link_utp)
		ytphy_write_ext(phydev, 0x9000, 0x0);

	return 0;
}

#if (KERNEL_VERSION(5, 6, 0) > LINUX_VERSION_CODE)
static int yt8011_ptp_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
{
	struct yt8xxx_priv *priv = phydev->priv;
	struct yt_ptp_private *ptp_priv = priv->ptp_priv;
	struct hwtstamp_config cfg;
	u16 cfg0 = 0, cfg1 = 0;
	//u16 role;

	//dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
		return -EFAULT;

	if (cfg.flags) /* reserved for future extensions */
		return -EINVAL;

	if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ONESTEP_SYNC)
		return -ERANGE;

	ptp_priv->tx_type = cfg.tx_type;

	dbg_ptp("@jie.han %s, %s, %d cfg.rx_filter: %s\n",
		__FILE__, __func__, __LINE__,
		cfg.rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT ? "HWTSTAMP_FILTER_PTP_V2_EVENT" : "other");
	switch (cfg.rx_filter) {
	case HWTSTAMP_FILTER_NONE:
	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
		ptp_priv->hwts_rx = 0;
		ptp_priv->layer = 0;
		ptp_priv->version = 0;
		break;
	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
		ptp_priv->hwts_rx = 1;
		ptp_priv->layer = PTP_CLASS_L4;
		ptp_priv->version = PTP_CLASS_V2;
		break;
	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
		//YT8011 default 802.1as enable
		ptp_priv->hwts_rx = 1;
		ptp_priv->layer = PTP_CLASS_L2;
		ptp_priv->version = PTP_CLASS_V2;
		break;
	case HWTSTAMP_FILTER_PTP_V2_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
		ptp_priv->hwts_rx = 1;
		ptp_priv->layer = PTP_CLASS_L4 | PTP_CLASS_L2;
		ptp_priv->version = PTP_CLASS_V2;
		break;
	default:
		return -ERANGE;
	}

	cfg0 |= OC_2_STEPS;
	dbg_ptp("@jie.han %s, %s, %d role: %s\n",
		__FILE__, __func__, __LINE__,
		priv->role == MASTER ? "MASTER" : "SLAVE");
	if (priv->role == MASTER)
		cfg0 |= (DAC_CLK << 2);
	else
		cfg0 |= (ADC_CLK_AFTER_ROTATOR << 2);

	/* ext reg 0x8000 bit4 BP_1588
	 * 1'b0 = PTP timestamp engine normal operation as default.
	 * 1'b1 = Bypass IEEE1588v2 related functions.
	 */
	cfg0 &= ~BIT(4);
	
	/* ext reg 0x8000 bit7 EN_GATE_1588
	 * 1'b0 = Disable gating 1588 clock domain.
	 * 1'b1 = Enable gating 1588 clock domain as default.
	 */
	cfg0 &= ~BIT(7);

	/* ext reg 0x8001 bit4 PTP_MODE_SEL
	 * 1'b1: PTP mode
	 * 1'b0: gPTP mode(802.1AS) as default
	 */
	if (ptp_priv->layer & PTP_CLASS_L2)
		cfg1 &= ~BIT(4);

	mutex_lock(&ptp_priv->mutex);
	yt8011_ptp_init_paged(phydev, cfg0, cfg1, YT8011_REG_SPACE_UTP);
	mutex_unlock(&ptp_priv->mutex);

	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}

static int parsing_ptp_msgtype_seqid(struct sk_buff *skb,
				     u8 *msgtype, u16 *seqid, int type)
{
	u8 *data = skb_mac_header(skb);
	unsigned int offset = 0;
	u8 *msg_type;
	//u16 *seq_id;

	//dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	if (type & PTP_CLASS_VLAN)
		offset += VLAN_HLEN;

	switch (type & PTP_CLASS_PMASK) {
	case PTP_CLASS_IPV4:
		offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;
		break;
	case PTP_CLASS_IPV6:
		offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;
		break;
	case PTP_CLASS_L2:
		offset += ETH_HLEN;
		break;
	default:
		return 0;
	}

	if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid))
		return 0;

	if (unlikely(type & PTP_CLASS_V1)) {
		if (offset + OFF_PTP_CONTROL >= skb->len)
			return 0;
		msg_type = data + offset + OFF_PTP_CONTROL;
	} else {
		if (offset >= skb->len)
			return 0;
		msg_type = data + offset;
	}
	//memcpy(msgtype, msg_type, sizeof(*msgtype));
	*msgtype = (*msg_type) & 0xf;

	//seq_id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
	//memcpy(seqid, seq_id, sizeof(*seqid));
	//*seq_id = ntohs(*(u16 *)(data + offset + OFF_PTP_SEQUENCE_ID));
	*seqid = ntohs(*(u16 *)(data + offset + OFF_PTP_SEQUENCE_ID));
	dbg_ptp("@jie.han %s, %s, %d msgtype: %s, seq_id: %d\n",
		__FILE__, __func__, __LINE__,
		*msgtype == SYNC ? "SYNC" :
		*msgtype == DELAY_REQ ? "DELAY_REQ" :
		*msgtype == PDELAY_REQ ? "PDELAY_REQ" :
		*msgtype == PDELAY_RESP ? "PDELAY_RESP" :
		*msgtype == FOLLOW_UP ? "FOLLOW_UP" :
		*msgtype == DELAY_RESP ? "DELAY_RESP" :
		*msgtype == PDELAY_RESP_FOLLOW_UP ? "PDELAY_RESP_FOLLOW_UP" :
		*msgtype == ANNOUNCE ? "ANNOUNCE" :
		*msgtype == SIGNALING ? "SIGNALING" :
		*msgtype == MANAGEMENT ? "MANAGEMENT" : "others", *seqid);
	return 1;
}

static bool yt8011_ptp_rxtstamp(struct phy_device *phydev,
				struct sk_buff *skb, int type)
{
	struct skb_shared_hwtstamps *shhwtstamps;
	struct yt8xxx_priv *priv = phydev->priv;
	u16 sequence_id;
	u32 sec = 0, nsec = 0;
	u8 msg_type;
	int ret;

	dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	if (!priv->ptp_priv->hwts_rx)
		return false;

	if ((type & priv->ptp_priv->version) == 0 ||
		(type & priv->ptp_priv->layer) == 0)
		return false;

	dbg_ptp("@jie.han %s, %s, %d call parsing_ptp_msgtype_seqid()\n",
		__FILE__, __func__, __LINE__);
	parsing_ptp_msgtype_seqid(skb, &msg_type, &sequence_id, type);
	dbg_ptp("@jie.han %s, %s, %d after parsing_ptp_msgtype_seqid() "
		"msg_type: %s, sequence_id: %d\n",
		__FILE__, __func__, __LINE__,
		msg_type == SYNC ? "SYNC" :
		msg_type == DELAY_REQ ? "DELAY_REQ" :
		msg_type == PDELAY_REQ ? "PDELAY_REQ" :
		msg_type == PDELAY_RESP ? "PDELAY_RESP" :
		msg_type == FOLLOW_UP ? "FOLLOW_UP" :
		msg_type == DELAY_RESP ? "DELAY_RESP" :
		msg_type == PDELAY_RESP_FOLLOW_UP ? "PDELAY_RESP_FOLLOW_UP" :
		msg_type == ANNOUNCE ? "ANNOUNCE" :
		msg_type == SIGNALING ? "SIGNALING" :
		msg_type == MANAGEMENT ? "MANAGEMENT" : "other", sequence_id);
	dbg_ptp("@jie.han %s, %s, %d call yt8011_ptp_get_rxtstamp_paged()\n",
		__FILE__, __func__, __LINE__);
	ret = yt8011_ptp_get_rxtstamp_paged(phydev, msg_type,
					    sequence_id, &sec, &nsec,
					    YT8011_REG_SPACE_UTP);
	if (ret > 0) {
		shhwtstamps = skb_hwtstamps(skb);
		shhwtstamps->hwtstamp = ktime_set(sec, nsec);
		dbg_ptp("@jie.han %s, %s, %d "
			"shhwtstamps->hwtstamp: %lld then call netif_rx()\n",
			__FILE__, __func__, __LINE__, shhwtstamps->hwtstamp);
		netif_rx(skb);
		return true;
	} else
		return false;
}

#define SKB_TIMESTAMP_TIMEOUT	10 /* jiffies */

static void yt8011_ptp_txtstamp(struct phy_device *phydev,
				struct sk_buff *skb, int type)
{
	struct yt8xxx_priv *priv = phydev->priv;
	struct yt_ptp_private *ptp_priv = priv->ptp_priv;
	u8 msgtype;
	u16 seqid;

#if 0
	dbg_ptp("@jie.han %s, %s, %d ptp_priv->tx_type: %s",
		__FILE__, __func__, __LINE__,
		ptp_priv->tx_type == HWTSTAMP_TX_ON ? "HWTSTAMP_TX_ON" :
		ptp_priv->tx_type == HWTSTAMP_TX_ONESTEP_SYNC ? "HWTSTAMP_TX_ONESTEP_SYNC" :
		ptp_priv->tx_type == HWTSTAMP_TX_OFF ? "HWTSTAMP_TX_OFF" : "others");
#endif
	//parsing_ptp_msgtype_seqid(skb, &msgtype, &seqid, type);
	switch (ptp_priv->tx_type) {
	case HWTSTAMP_TX_ON:
		dbg_ptp("@jie.han %s, %s, %d ptp_priv->tx_type: HWTSTAMP_TX_ON\n",
			__FILE__, __func__, __LINE__);
		dbg_ptp("@jie.han %s, %s, %d skb: %p, skb->sk: %p, "
			"skb->sk->sk_flags: %#lx, tx_flags: 0x%x\n",
			__FILE__, __func__, __LINE__,
			skb, skb->sk, skb->sk->sk_flags, skb_shinfo(skb)->tx_flags);
		if (!skb->sk) {
			kfree_skb(skb);
			return;
		}

		if (!parsing_ptp_msgtype_seqid(skb, &msgtype, &seqid, type)) {
			pr_err("@jie.han %s, %s, %d parsing skb failed, drop skb.\n",
				__FILE__, __func__, __LINE__);
			kfree_skb(skb);
			return;
		}
		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
		memset(YT_SKB_CB(skb), 0x0, sizeof(struct yt_ptp_skb_cb));
		YT_SKB_CB(skb)->timeout = jiffies + SKB_TIMESTAMP_TIMEOUT;
		YT_SKB_CB(skb)->seq_id = seqid;
		YT_SKB_CB(skb)->msgtype = msgtype;
		//if (skb->sk)
		/* increment the reference count to prevent premature release */
		sock_hold(skb->sk);
		dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_flags: %#lx\n",
			__FILE__, __func__, __LINE__, skb->sk->sk_flags);
		//dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_refcnt: %d\n",
		//	__FILE__, __func__, __LINE__, atomic_read(&skb->sk->sk_refcnt));
		dbg_ptp("@jie.han %s, %s, %d skb->sk->sk_refcnt: %d\n",
			__FILE__, __func__, __LINE__, skb->sk->sk_refcnt.refs.counter);
		skb_queue_tail(&ptp_priv->tx_queue, skb);
		ptp_schedule_worker(priv->ptp_priv->clock, 0);
		break;
	case HWTSTAMP_TX_ONESTEP_SYNC:
		dbg_ptp("@jie.han %s, %s, %d ptp_priv->tx_type: HWTSTAMP_TX_ONESTEP_SYNC\n",
			__FILE__, __func__, __LINE__);
		//__fallthrough;
	case HWTSTAMP_TX_OFF:
	default:
		kfree_skb(skb);
		break;
	}
}

static int yt8011_ptp_ts_info(struct phy_device *phydev,
			      struct ethtool_ts_info *info)
{
	struct yt8xxx_priv *priv = phydev->priv;

	info->so_timestamping =
		SOF_TIMESTAMPING_TX_SOFTWARE |
		SOF_TIMESTAMPING_RX_SOFTWARE |
		SOF_TIMESTAMPING_SOFTWARE |
		SOF_TIMESTAMPING_TX_HARDWARE |
		SOF_TIMESTAMPING_RX_HARDWARE |
		SOF_TIMESTAMPING_RAW_HARDWARE;
	info->phc_index = ptp_clock_index(priv->ptp_priv->clock);
	dbg_ptp("@jie.han %s, %s, %d info->phc_index: %d\n",
		__FILE__, __func__, __LINE__, info->phc_index);
	info->tx_types =
		(1 << HWTSTAMP_TX_OFF) |
		(1 << HWTSTAMP_TX_ON);
	info->rx_filters =
		(1 << HWTSTAMP_FILTER_NONE) |
		(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
		(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
		(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
	return 0;
}
#endif

static void yt8011_remove(struct phy_device *phydev)
{
	struct yt8xxx_priv *priv = phydev->priv;
	struct yt_ptp_private *ptp_priv = priv->ptp_priv;

	dbg_ptp("@jie.han %s, %s, %d\n", __FILE__, __func__, __LINE__);
	if (ptp_priv->clock)
		ptp_clock_unregister(ptp_priv->clock);

	skb_queue_purge(&ptp_priv->tx_queue);
}

#if (KERNEL_VERSION(4, 4, 302) < LINUX_VERSION_CODE)
static int __yt8011_write_page(struct phy_device *phydev, int page)
{
	int ret;

	ret = __ytphy_read_ext(phydev, YT801X_REG_SMI_MUX);
	if (ret < 0)
		return ret;

	if (page == YT8011_REG_SPACE_UTP)
		return __ytphy_write_ext(phydev, YT801X_REG_SMI_MUX,
					 ret & (~BIT(15)));
	else if (page == YT8011_REG_SPACE_SDS)
		return __ytphy_write_ext(phydev, YT801X_REG_SMI_MUX,
					 ret | BIT(15));
	return 0;
}

static int __yt8011_read_page(struct phy_device *phydev)
{
	int ret;
	
	ret = __ytphy_read_ext(phydev, YT801X_REG_SMI_MUX);
	if (ret < 0)
		return ret;

	if (ret & BIT(15))
		return YT8011_REG_SPACE_SDS;
	else
		return YT8011_REG_SPACE_UTP;
}

static int yt8011_save_page(struct phy_device *phydev)
{
	/* mutex_lock(&phydev->mdio.bus->mdio_lock); */
	phy_lock_mdio_bus(phydev);
	
	return __yt8011_read_page(phydev);
}

static int yt8011_select_page(struct phy_device *phydev, int page)
{
	int ret, oldpage;

	oldpage = ret = yt8011_save_page(phydev);
	if (ret < 0)
		return ret;

	if (oldpage != page) {
		ret = __yt8011_write_page(phydev, page);
		if (ret < 0)
			return ret;
	}

	return oldpage;
}

static int yt8011_restore_page(struct phy_device *phydev, int oldpage, int ret)
{
	int r;

	if (oldpage >= 0) {
		r = __yt8011_write_page(phydev, oldpage);

		/* Propagate the operation return code if the page write
		 * was successful.
		 */
		if (ret >= 0 && r < 0)
			ret = r;
	} else {
		/* Propagate the phy page selection error code */
		ret = oldpage;
	}

	/* mutex_unlock(&phydev->mdio.bus->mdio_lock); */
	phy_unlock_mdio_bus(phydev);

	return ret;
}
#endif

static int yt801x_config_intr(struct phy_device *phydev)
{
	int ret;

	ret = ytphy_write_ext(phydev, YT801X_REG_SMI_MUX,
			      YTPHY_REG_SPACE_UTP);
	if (ret < 0)
		return ret;

	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
		ret = phy_write(phydev, YTPHY_UTP_INTR_REG,
				YTPHY_INTR_LINK_STATUS);

	return ret;
}

#if (KERNEL_VERSION(5, 10, 232) < LINUX_VERSION_CODE)
static irqreturn_t ytphy_handle_interrupt(struct phy_device *phydev)
{
	int ret;

	ret = phy_read(phydev, YTPHY_UTP_INTR_STATUS_REG);
	if (ret > 0) {
		phy_trigger_machine(phydev);
		return IRQ_HANDLED;
	}
	else
		return IRQ_NONE;
}

static irqreturn_t yt801x_handle_interrupt(struct phy_device *phydev)
{
	int ret;

	ret = ytphy_write_ext(phydev, YT801X_REG_SMI_MUX,
			      YTPHY_REG_SPACE_UTP);
	if (ret < 0)
		return IRQ_NONE;

	ret = phy_read(phydev, YTPHY_UTP_INTR_STATUS_REG);
	if (ret > 0) {
		phy_trigger_machine(phydev);
		return IRQ_HANDLED;
	}
	else
		return IRQ_NONE;
}
#else
static int yt801x_ack_interrupt(struct phy_device *phydev)
{
	int ret;

	ret = ytphy_write_ext(phydev, YT801X_REG_SMI_MUX,
			      YTPHY_REG_SPACE_UTP);
	if (ret < 0)
		return ret;

	ret = phy_read(phydev, YTPHY_UTP_INTR_STATUS_REG);
	return ret < 0 ? ret : 0;
}
#endif

static struct phy_driver ytphy_drvs[] = {
	{
		.phy_id		= PHY_ID_YT8011,
		.name		= "YT8011 Automotive Gigabit Ethernet",
		.phy_id_mask	= MOTORCOMM_PHY_ID_MASK,
		.features	= PHY_GBIT_FEATURES,
		.config_intr	= yt801x_config_intr,
#if (KERNEL_VERSION(5, 10, 232) < LINUX_VERSION_CODE)
		.handle_interrupt	= yt801x_handle_interrupt,
#else
		.ack_interrupt	= yt801x_ack_interrupt,
#endif
		.probe		= yt8011_probe,
#if (KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE)
#else
		.soft_reset	= yt8011_soft_reset,
#endif
		.config_aneg	= yt8011_config_aneg,
#if (KERNEL_VERSION(3, 14, 79) < LINUX_VERSION_CODE)
		.aneg_done	= yt8011_aneg_done,
#endif
		.config_init	= yt8011_config_init,
		.read_status	= yt8011_read_status,
#if (KERNEL_VERSION(5, 6, 0) > LINUX_VERSION_CODE)
		.ts_info	= yt8011_ptp_ts_info,
		.hwtstamp	= yt8011_ptp_hwtstamp,
		.rxtstamp	= yt8011_ptp_rxtstamp,
		.txtstamp	= yt8011_ptp_txtstamp,
#endif
		.remove		= yt8011_remove,
		//.suspend		= yt8011_suspend,
	},
};

#if (KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE)
static int ytphy_drivers_register(struct phy_driver *phy_drvs, int size)
{
	int i, j;
	int ret;

	for (i = 0; i < size; i++) {
		ret = phy_driver_register(&phy_drvs[i]);
		if (ret)
			goto err;
	}

	return 0;

err:
	for (j = 0; j < i; j++)
		phy_driver_unregister(&phy_drvs[j]);

	return ret;
}

static void ytphy_drivers_unregister(struct phy_driver *phy_drvs, int size)
{
	int i;

	for (i = 0; i < size; i++)
		phy_driver_unregister(&phy_drvs[i]);
}

static int __init ytphy_init(void)
{
	return ytphy_drivers_register(ytphy_drvs, ARRAY_SIZE(ytphy_drvs));
}

static void __exit ytphy_exit(void)
{
	pr_info(MODULE_NAME ": Module unloaded\n");
	ytphy_drivers_unregister(ytphy_drvs, ARRAY_SIZE(ytphy_drvs));
}

module_init(ytphy_init);
module_exit(ytphy_exit);
#else
/* for linux 4.x ~ */
/* module_phy_driver(ytphy_drvs);*/
static int __init phy_module_init(void)
{
	return phy_drivers_register(ytphy_drvs, ARRAY_SIZE(ytphy_drvs),
				    THIS_MODULE);
}

static void __exit phy_module_exit(void)
{
	pr_info(MODULE_NAME ": Module unloaded\n");

	phy_drivers_unregister(ytphy_drvs, ARRAY_SIZE(ytphy_drvs));
}

module_init(phy_module_init);
module_exit(phy_module_exit);
#endif

MODULE_DESCRIPTION("Motorcomm PHY driver");
MODULE_VERSION(YTPHY_LINUX_VERSION);	/* for modinfo xxxx.ko in userspace */
MODULE_AUTHOR("Jie Han");
MODULE_LICENSE("GPL");

static struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
	{ PHY_ID_YT8011, MOTORCOMM_PHY_ID_MASK },
	{ }
};

MODULE_DEVICE_TABLE(mdio, motorcomm_tbl);

  • 10. disabled CONFIG_TI_CPTS in .config

  • 您好,

    已经收到了您的案例,调查需要些时间,感谢您的耐心等待。

  • updated info for u.
    after today's debug, committed the debug log on master side in kernel and phy driver based on latest motorcomm(29).c
    1. found skb and skb->sk pointer are same all the time, not be changed.
    eg. in file master-0512.txt
    at first:
    line 158 skb->sk: fbb434bf
    line 160 the skb cloned, clone(skb): 0c9fa107

    in the end, matched skb enqueued into err queue.
    line 196 before call skb_queue_tail(&sk->sk_error_queue, skb) skb: 0c9fa107
    line 197 before call skb_queue_tail(&sk->sk_error_queue, skb) skb->sk: fbb434bf
    and line 198 sk->sk_flags: 0x800100 (not SOCK_DEAD)
    and ling 199 sk->sk_error_queue.qlen: 0x1(skb enqueued) and call sk->sk_error_report(sk) => sock_def_error_report() to wake up poll()

    root@am335x-evm:~/phy_ptp# ./ptp4l -f cfg -i eth0 -m -l 7
    ptp4l[59.712]: config item (null).assume_two_step is 1
    ptp4l[59.715]: config item (null).check_fup_sync is 0
    ptp4l[59.716]: config item (null).tx_timestamp_timeout is 1
    ptp4l[59.716]: config item (null).hwts_filter is 0
    ptp4l[59.717]: config item (null).clock_servo is 0
    [   59.733258] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_ts_info, 2136 info->phc_index: 0
    ptp4l[59.717]: config item (null).clock_type is 32768
    ptp4l[59.719]: config item (null).clock_servo is 0
    ptp4l[59.720]: config item (null).clockClass is 248
    ptp4l[59.720]: config item (null).clockAccuracy is 254
    ptp4l[59.721]: config item (null).offsetScaledLogVariance is 65535
    [   59.761646] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_adjfine, 633 scaled_ppm: 0
    ptp4l[59.721]: config item (null).productDescription is ';;'
    ptp4l[59.722]: config item (null).revisionData is ';;'
    ptp4l[59.722]: config item (null).userDescription is ''
    ptp4l[59.723]: config item (null).manufacturerIdentity is '00:00:00'
    ptp4l[59.723]: config item (null).domainNumber is 0
    ptp4l[59.723]: config item (null).slaveOnly is 0
    ptp4l[59.724]: config item (null).gmCapable is 1
    ptp4l[59.724]: config item (null).gmCapable is 1
    ptp4l[59.725]: config item (null).G.8275.defaultDS.localPriority is 128
    ptp4l[59.725]: config item (null).maxStepsRemoved is 255
    ptp4l[59.726]: config item (null).time_stamping is 1
    ptp4l[59.726]: config item (null).twoStepFlag is 1
    ptp4l[59.726]: config item (null).twoStepFlag is 1
    ptp4l[59.727]: config item (null).time_stamping is 1
    ptp4l[59.727]: config item (null).priority1 is 248
    ptp4l[59.728]: config item (null).priority2 is 248
    ptp4l[59.731]: interface index 2 is up
    ptp4l[59.744]: config item (null).free_running is 0
    ptp4l[59.745]: selected /dev/ptp0 as PTP clock
    ptp4l[59.745]: config item (null).clockIdentity is '000000.0000.000000'
    ptp4l[59.747]: config item (null).uds_address is '/var/run/ptp4l'
    ptp4l[59.748]: section item /var/run/ptp4l.announceReceiptTimeout now 0
    ptp4l[59.748]: section item /var/run/ptp4l.delay_mechanism now 0
    ptp4l[59.749]: section item /var/run/ptp4l.network_transport now 0
    ptp4l[59.749]: section item /var/run/ptp4l.delay_filter_length now 1
    ptp4l[59.749]: config item (null).free_running is 0
    ptp4l[59.751]: config item (null).freq_est_interval is 1
    ptp4l[59.751]: config item (null).write_phase_mode is 0
    ptp4l[59.752]: config item (null).gmCapable is 1
    ptp4l[59.752]: config item (null).kernel_leap is 1
    ptp4l[59.752]: config item (null).utc_offset is 37
    ptp4l[59.753]: config item (null).timeSource is 160
    ptp4l[59.777]: config item (null).pi_proportional_const is 0.000000
    ptp4l[59.778]: config item (null).pi_integral_const is 0.000000
    ptp4l[59.779]: config item (null).pi_proportional_scale is 0.000000
    ptp4l[59.779]: config item (null).pi_proportional_exponent is -0.300000
    ptp4l[59.780]: config item (null).pi_proportional_norm_max is 0.700000
    ptp4l[59.782]: config item (null).pi_integral_scale is 0.000000
    ptp4l[59.782]: config item (null).pi_integral_exponent is 0.400000
    ptp4l[59.783]: config item (null).pi_integral_norm_max is 0.300000
    ptp4l[59.783]: config item (null).step_threshold is 0.000000
    ptp4l[59.784]: config item (null).first_step_threshold is 0.000020
    ptp4l[59.784]: config item (null).max_frequency is 900000000
    ptp4l[59.784]: config item (null).servo_offset_threshold is 0
    ptp4l[59.785]: config item (null).servo_num_offset_values is 10
    ptp4l[59.785]: config item (null).dataset_comparison is 0
    ptp4l[59.786]: config item (null).tsproc_mode is 0
    ptp4l[59.786]: config item (null).delay_filter is 1
    ptp4l[59.787]: config item (null).delay_filter_length is 10
    ptp4l[59.789]: config item (null).initial_delay is 0
    ptp4l[59.790]: config item (null).summary_interval is 0
    ptp4l[59.791]: config item (null).sanity_freq_limit is 200000000
    ptp4l[59.799]: PI servo: sync interval 1.000 kp 0.700 ki 0.300000
    ptp4l[59.802]: config item /var/run/ptp4l.boundary_clock_jbod is 0
    ptp4l[59.802]: config item /var/run/ptp4l.network_transport is 0
    ptp4l[59.803]: config item /var/run/ptp4l.masterOnly is 1
    ptp4l[59.803]: config item /var/run/ptp4l.BMCA is 1
    ptp4l[59.803]: config item /var/run/ptp4l.delayAsymmetry is 0
    ptp4l[59.804]: config item /var/run/ptp4l.follow_up_info is 1
    ptp4l[59.804]: config item /var/run/ptp4l.freq_est_interval is 1
    ptp4l[59.805]: config item /var/run/ptp4l.msg_interval_request is 0
    ptp4l[59.805]: config item /var/run/ptp4l.net_sync_monitor is 0
    ptp4l[59.806]: config item /var/run/ptp4l.path_trace_enabled is 1
    ptp4l[59.806]: config item /var/run/ptp4l.tc_spanning_tree is 0
    ptp4l[59.806]: config item /var/run/ptp4l.ingressLatency is 0
    ptp4l[59.807]: config item /var/run/ptp4l.egressLatency is 0
    ptp4l[59.809]: config item /var/run/ptp4l.delay_mechanism is 0
    ptp4l[59.811]: config item /var/run/ptp4l.hybrid_e2e is 0
    ptp4l[59.812]: config item /var/run/ptp4l.fault_badpeernet_interval is 16
    ptp4l[59.812]: config item /var/run/ptp4l.fault_reset_interval is 4
    ptp4l[59.812]: config item /var/run/ptp4l.tsproc_mode is 0
    ptp4l[59.813]: config item /var/run/ptp4l.delay_filter is 1
    ptp4l[59.813]: config item /var/run/ptp4l.delay_filter_length is 1
    ptp4l[59.815]: config item (null).slave_event_monitor is ''
    ptp4l[59.817]: config item eth0.boundary_clock_jbod is 0
    ptp4l[60.152]: config item eth0.network_transport is 3
    ptp4l[60.153]: config item eth0.masterOnly is 1
    ptp4l[60.153]: config item eth0.BMCA is 1
    ptp4l[60.154]: config item eth0.delayAsymmetry is 0
    ptp4l[60.154]: config item eth0.follow_up_info is 1
    ptp4l[60.154]: config item eth0.freq_est_interval is 1
    ptp4l[60.155]: config item eth0.msg_interval_request is 0
    ptp4l[60.155]: config item eth0.net_sync_monitor is 0
    ptp4l[60.156]: config item eth0.path_trace_enabled is 1
    ptp4l[60.156]: config item eth0.tc_spanning_tree is 0
    ptp4l[60.156]: config item eth0.ingressLatency is 0
    [   60.229754] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_hwtstamp, 1872 cfg.tx_type: HWTSTAMP_TX_ON, cfg.rx_filter: HWTSTAMP_FILTER_PTP_V2_EVENT
    ptp4l[60.157]: config item eth0.egressLatency is 0
    [   60.243331] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_hwtstamp, 1911 role: MASTER
    ptp4l[60.157]: config item eth0.delay_mechanism is 2
    ptp4l[60.158]: config item eth0.unicast_master_table is 0
    ptp4l[60.158]: config item eth0.unicast_listen is 0
    ptp4l[60.159]: config item eth0.hybrid_e2e is 0
    ptp4l[60.159]: config item eth0.fault_badpeernet_interval is 16
    ptp4l[60.160]: config item eth0.fault_reset_interval is 4
    ptp4l[60.160]: config item eth0.tsproc_mode is 0
    ptp4l[60.161]: config item eth0.delay_filter is 1
    ptp4l[60.161]: config item eth0.delay_filter_length is 10
    ptp4l[60.163]: config item eth0.logMinDelayReqInterval is 0
    ptp4l[60.164]: config item eth0.logAnnounceInterval is 1
    ptp4l[60.164]: config item eth0.inhibit_announce is 1
    ptp4l[60.165]: config item eth0.ignore_source_id is 0
    ptp4l[60.165]: config item eth0.announceReceiptTimeout is 3
    ptp4l[60.166]: config item eth0.syncReceiptTimeout is 3
    ptp4l[60.166]: config item eth0.transportSpecific is 1
    ptp4l[60.166]: config item eth0.ignore_transport_specific is 0
    ptp4l[60.167]: config item eth0.G.8275.portDS.localPriority is 128
    ptp4l[60.167]: config item eth0.logSyncInterval is 0
    ptp4l[60.168]: config item eth0.operLogSyncInterval is 0
    ptp4l[60.168]: config item eth0.logMinPdelayReqInterval is 0
    ptp4l[60.169]: config item eth0.operLogPdelayReqInterval is 0
    ptp4l[60.169]: config item eth0.neighborPropDelayThresh is 800
    ptp4l[60.169]: config item eth0.min_neighbor_prop_delay is -20000000
    ptp4l[60.170]: config item eth0.asCapable is 0
    ptp4l[60.171]: config item eth0.inhibit_delay_req is 1
    ptp4l[60.173]: config item eth0.ptp_dst_mac is '01:80:C2:00:00:0E'
    ptp4l[60.175]: config item eth0.p2p_dst_mac is '01:80:C2:00:00:0E'
    ptp4l[60.176]: config item global.socket_priority is 0
    ptp4l[60.267]: port 1: INITIALIZING to MASTER on INIT_COMPLETE
    ptp4l[60.271]: config item /var/run/ptp4l.logMinDelayReqInterval is 0
    ptp4l[60.272]: config item /var/run/ptp4l.logAnnounceInterval is 1
    ptp4l[60.273]: config item /var/run/ptp4l.inhibit_announce is 1
    ptp4l[60.273]: config item /var/run/ptp4l.ignore_source_id is 0
    ptp4l[60.273]: config item /var/run/ptp4l.announceReceiptTimeout is 0
    ptp4l[60.274]: config item /var/run/ptp4l.syncReceiptTimeout is 3
    ptp4l[60.274]: config item /var/run/ptp4l.transportSpecific is 1
    ptp4l[60.275]: config item /var/run/ptp4l.ignore_transport_specific is 0
    ptp4l[60.275]: config item /var/run/ptp4l.G.8275.portDS.localPriority is 128
    ptp4l[60.276]: config item /var/run/ptp4l.logSyncInterval is 0
    ptp4l[60.276]: config item /var/run/ptp4l.operLogSyncInterval is 0
    ptp4l[60.276]: config item /var/run/ptp4l.logMinPdelayReqInterval is 0
    ptp4l[60.277]: config item /var/run/ptp4l.operLogPdelayReqInterval is 0
    ptp4l[60.277]: config item /var/run/ptp4l.neighborPropDelayThresh is 800
    ptp4l[60.278]: config item /var/run/ptp4l.min_neighbor_prop_delay is -20000000
    ptp4l[60.278]: config item /var/run/ptp4l.asCapable is 0
    ptp4l[60.278]: config item /var/run/ptp4l.inhibit_delay_req is 1
    ptp4l[60.279]: config item (null).uds_address is '/var/run/ptp4l'
    ptp4l[60.280]: port 0: INITIALIZING to LISTENING on INIT_COMPLETE
    ptp4l[60.281]: port 1: received link status notification
    ptp4l[60.282]: interface index 2 is up
    ptp4l[61.272]: port 1: master sync timeout
    [   61.273174] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 65 type: 0x42
    [   61.283516] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 70 type: PTP_CLASS_L2 | PTP_CLASS_V2
    [   61.294153] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 77 skb->sk: fbb434bf
    [   61.302936] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4371 before call skb_clone(skb, GFP_ATOMIC) skb->sk: fbb434bf
    [   61.314512] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4382 after call skb_clone(skb, GFP_ATOMIC) clone(skb): 0c9fa107, clone->sk:   (null)
    [   61.328088] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4387 assign sk: fbb434bf to clone->sk: fbb434bf
    [   61.338395] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 83 clone->sk: fbb434bf
    [   61.347183] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2075 ptp_priv->tx_type: HWTSTAMP_TX_ON
    [   61.357551] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2079 skb: 0c9fa107, skb->sk: fbb434bf, skb->sk->sk_flags: 0x800100, tx_flags: 0x1
    [   61.371633] @jie.han drivers/net/phy/motorcomm.c, parsing_ptp_msgtype_seqid, 1999 msgtype: SYNC, seq_id: 0
    [   61.381671] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2101 before call skb_queue_tail(&ptp_priv->tx_queue, skb); skb->sk: fbb434bf
    [   61.395234] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2103 skb->sk->sk_flags: 0x800100
    [   61.404994] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2107 skb->sk->sk_refcnt: 5
    ptp4l[61.416]: timed out while polling for tx timestamp
    [   61.419242] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_get_txtstamp, 739 yt_ptp_get_txtstamp_paged() ret: 0, capts->seq_id: 0, capts->msgtype: SYNC
    ptp4l[61.417]: @jie.han increasing tx_timestamp_timeout may correct this issue, but it is likely caused by a driver bug
    [   61.435892] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 762 scan ptp_priv->tx_queue, skb->sk: fbb434bf
    ptp4l[61.418]: @jie.han fd: 14 errno: -6
    [   61.452004] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 764 skb->sk->sk_flags: 0x800100
    ptp4l[61.419]: port 1: send sync failed
    [   61.467864] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 770 skb->sk->sk_refcnt: 3
    ptp4l[61.430]: port 1: MASTER to FAULTY on FAULT_DETECTED (FT_UNSPECIFIED)
    [   61.482807] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 786 skb->sk->sk_flags: 0x800100
    [   61.498599] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 808 matched, seqid: 0, msgtype: SYNC
    [   61.511218] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 811 matched, skb->sk: fbb434bf
    [   61.521482] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 818 skb->sk->sk_flags: 0x800100
    [   61.531725] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 822 before call skb_complete_tx_timestamp() skb: 0c9fa107
    [   61.544234] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 825 before call skb_complete_tx_timestamp() skb->sk: fbb434bf
    [   61.557098] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 829 before call skb_complete_tx_timestamp() shhwtstamps->hwtstamp: 0xd234ccf96d137fb
    [   61.571966] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4461 skb->sk->sk_flags: 0x800100
    [   61.582075] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4473 assigned hwtstamps: 0xd234ccf96d137fb to skb then call __skb_complete_tx_timestamp(SCM_TSTAMP_SND)
    [   61.598394] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4475 sk->sk_refcnt: 4
    [   61.607494] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4480 skb: 0c9fa107, skb->sk: fbb434bf
    [   61.618054] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4424 skb enqueued(sock_queue_err_skb() called), tstamp: 946684835629620360, skb: 0c9fa107, skb->sk: fbb434bf
    [   61.635020] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4428 skb->sk->sk_error_queue.qlen: 0x0
    [   61.645826] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4430 skb->sk->sk_flags: 0x800100
    [   61.656121] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4256 skb->sk->sk_flags: 0x800100
    [   61.665572] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4267 skb->sk:   (null)
    [   61.674199] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4269 sk: fbb434bf
    [   61.682345] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4277 skb->sk->sk_flags: 0x800100
    [   61.691853] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4285 before call skb_queue_tail(&sk->sk_error_queue, skb) skb: 0c9fa107
    [   61.704710] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4289 before call skb_queue_tail(&sk->sk_error_queue, skb) skb->sk: fbb434bf
    [   61.717956] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4296 sk->sk_flags: 0x800100
    [   61.726966] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4308 sk->sk_error_queue.qlen: 0x1 and call sk->sk_error_report(sk)
    [   61.739506] sock: @jie.han net/core/sock.c, sock_def_error_report, 2701 wake up poll.
    [   61.747462] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_do_aux_work, 893 reschedule: false
    ptp4l[61.770]: waiting 2^{4} seconds to clear fault on port 1
    ptp4l[77.771]: clearing fault on port 1
    ptp4l[77.771]: config item eth0.logMinDelayReqInterval is 0
    ptp4l[77.772]: config item eth0.logAnnounceInterval is 1
    ptp4l[77.772]: config item eth0.inhibit_announce is 1
    ptp4l[77.772]: config item eth0.ignore_source_id is 0
    ptp4l[77.772]: config item eth0.announceReceiptTimeout is 3
    ptp4l[77.772]: config item eth0.syncReceiptTimeout is 3
    ptp4l[77.772]: config item eth0.transportSpecific is 1
    ptp4l[77.773]: config item eth0.ignore_transport_specific is 0
    ptp4l[77.773]: config item eth0.G.8275.portDS.localPriority is 128
    ptp4l[77.773]: config item eth0.logSyncInterval is 0
    ptp4l[77.773]: config item eth0.operLogSyncInterv[   77.829750] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_hwtstamp, 1872 cfg.tx_type: HWTSTAMP_TX_ON, cfg.rx_filter: HWTSTAMP_FILTER_PTP_V2_EVENT
    al is 0
    ptp4l[77.775]: config item eth0.logMinPdelayReqInterval[   77.843852] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_hwtstamp, 1911 role: MASTER
     is 0
    ptp4l[77.775]: config item eth0.operLogPdelayReqInterval is 0
    ptp4l[77.776]: config item eth0.neighborPropDelayThresh is 800
    ptp4l[77.776]: config item eth0.min_neighbor_prop_delay is -20000000
    ptp4l[77.777]: config item eth0.asCapable is 0
    ptp4l[77.777]: config item eth0.inhibit_delay_req is 1
    ptp4l[77.777]: config item eth0.ptp_dst_mac is '01:80:C2:00:00:0E'
    ptp4l[77.778]: config item eth0.p2p_dst_mac is '01:80:C2:00:00:0E'
    ptp4l[77.779]: config item global.socket_priority is 0
    ptp4l[77.867]: port 1: FAULTY to MASTER on INIT_COMPLETE
    ptp4l[77.868]: port 1: received link status notification
    ptp4l[77.868]: interface index 2 is up
    ptp4l[78.868]: port 1: master sync timeout[   78.868837] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 65 type: 0x42
    
    [   78.879263] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 70 type: PTP_CLASS_L2 | PTP_CLASS_V2
    [   78.890073] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 77 skb->sk: febeb217
    [   78.898410] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4371 before call skb_clone(skb, GFP_ATOMIC) skb->sk: febeb217
    [   78.910216] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4382 after call skb_clone(skb, GFP_ATOMIC) clone(skb): f39e2395, clone->sk:   (null)
    [   78.923789] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4387 assign sk: febeb217 to clone->sk: febeb217
    [   78.934156] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 83 clone->sk: febeb217
    [   78.943061] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2075 ptp_priv->tx_type: HWTSTAMP_TX_ON
    [   78.953388] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2079 skb: f39e2395, skb->sk: febeb217, skb->sk->sk_flags: 0x800100, tx_flags: 0x1
    [   78.967427] @jie.han drivers/net/phy/motorcomm.c, parsing_ptp_msgtype_seqid, 1999 msgtype: SYNC, seq_id: 1
    [   78.977452] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2101 before call skb_queue_tail(&ptp_priv->tx_queue, skb); skb->sk: febeb217
    [   78.991101] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2103 skb->sk->sk_flags: 0x800100
    [   79.000860] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2107 skb->sk->sk_refcnt: 5
    ptp4l[79.012]: timed out while polling for tx timestamp[   79.015304] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_get_txtstamp, 739 yt_ptp_get_txtstamp_paged() ret: 0, capts->seq_id: 1, capts->msgtype: SYNC
    
    ptp4l[79.013]: @jie.han increasing tx_timestamp_timeout may co[   79.031813] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 762 scan ptp_priv->tx_queue, skb->sk: febeb217
    rrect this issue, but it is likely caused by a driver bug
    ptp4l[   79.048987] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 764 skb->sk->sk_flags: 0x800100
    [79.014]: @jie.han fd: 14 errno: -6
    ptp4l[79.014]: port 1: send[   79.064488] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 770 skb->sk->sk_refcnt: 3
     sync failed
    ptp4l[79.015]: port 1: MASTER to FAULTY on FAULT_D[   79.079609] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 786 skb->sk->sk_flags: 0x800100
    ETECTED (FT_UNSPECIFIED)
    [   79.095541] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 808 matched, seqid: 1, msgtype: SYNC
    [   79.108456] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 811 matched, skb->sk: febeb217
    [   79.118580] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 818 skb->sk->sk_flags: 0x800100
    [   79.128925] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 822 before call skb_complete_tx_timestamp() skb: f39e2395
    [   79.141473] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 825 before call skb_complete_tx_timestamp() skb->sk: febeb217
    [   79.154287] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 829 before call skb_complete_tx_timestamp() shhwtstamps->hwtstamp: 0xd234ccf968aac73
    [   79.169075] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4461 skb->sk->sk_flags: 0x800100
    [   79.179179] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4473 assigned hwtstamps: 0xd234ccf968aac73 to skb then call __skb_complete_tx_timestamp(SCM_TSTAMP_SND)
    [   79.195450] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4475 sk->sk_refcnt: 4
    [   79.205061] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4480 skb: f39e2395, skb->sk: febeb217
    [   79.215847] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4424 skb enqueued(sock_queue_err_skb() called), tstamp: 946684853226561360, skb: f39e2395, skb->sk: febeb217
    [   79.232861] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4428 skb->sk->sk_error_queue.qlen: 0x0
    [   79.243675] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4430 skb->sk->sk_flags: 0x800100
    [   79.253952] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4256 skb->sk->sk_flags: 0x800100
    [   79.263398] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4267 skb->sk:   (null)
    [   79.272024] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4269 sk: febeb217
    [   79.280170] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4277 skb->sk->sk_flags: 0x800100
    [   79.289373] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4285 before call skb_queue_tail(&sk->sk_error_queue, skb) skb: f39e2395
    [   79.302575] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4289 before call skb_queue_tail(&sk->sk_error_queue, skb) skb->sk: febeb217
    [   79.315852] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4296 sk->sk_flags: 0x800100
    [   79.324875] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4308 sk->sk_error_queue.qlen: 0x1 and call sk->sk_error_report(sk)
    [   79.337341] sock: @jie.han net/core/sock.c, sock_def_error_report, 2701 wake up poll.
    [   79.345545] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_do_aux_work, 893 reschedule: false
    ptp4l[79.370]: waiting 2^{4} seconds to clear fault on port 1
    ptp4l[95.371]: clearing fault on port 1
    ptp4l[95.371]: config item eth0.logMinDelayReqInterval is 0
    ptp4l[95.372]: config item eth0.logAnnounceInterval is 1
    ptp4l[95.372]: config item eth0.inhibit_announce is 1
    ptp4l[95.372]: config item eth0.ignore_source_id is 0
    ptp4l[95.372]: config item eth0.announceReceiptTimeout is 3
    ptp4l[95.372]: config item eth0.syncReceiptTimeout is 3
    ptp4l[95.372]: config item eth0.transportSpecific is 1
    ptp4l[95.373]: config item eth0.ignore_transport_specific is 0
    ptp4l[95.373]: config item eth0.G.8275.portDS.localPriority is 128
    ptp4l[95.373]: config item eth0.logSyncInterval is 0
    ptp4l[95.373]: config item eth0.operLogSyncInterv[   95.429751] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_hwtstamp, 1872 cfg.tx_type: HWTSTAMP_TX_ON, cfg.rx_filter: HWTSTAMP_FILTER_PTP_V2_EVENT
    al is 0
    ptp4l[95.375]: config item eth0.logMinPdelayReqInterval[   95.443908] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_hwtstamp, 1911 role: MASTER
     is 0
    ptp4l[95.375]: config item eth0.operLogPdelayReqInterval is 0
    ptp4l[95.376]: config item eth0.neighborPropDelayThresh is 800
    ptp4l[95.376]: config item eth0.min_neighbor_prop_delay is -20000000
    ptp4l[95.376]: config item eth0.asCapable is 0
    ptp4l[95.377]: config item eth0.inhibit_delay_req is 1
    ptp4l[95.377]: config item eth0.ptp_dst_mac is '01:80:C2:00:00:0E'
    ptp4l[95.378]: config item eth0.p2p_dst_mac is '01:80:C2:00:00:0E'
    ptp4l[95.379]: config item global.socket_priority is 0
    ptp4l[95.467]: port 1: FAULTY to MASTER on INIT_COMPLETE
    ptp4l[95.467]: port 1: received link status notification
    ptp4l[95.468]: interface index 2 is up
    ptp4l[96.468]: port 1: master sync timeout[   96.469021] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 65 type: 0x42
    
    [   96.479315] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 70 type: PTP_CLASS_L2 | PTP_CLASS_V2
    [   96.490011] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 77 skb->sk: d09cc775
    [   96.498350] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4371 before call skb_clone(skb, GFP_ATOMIC) skb->sk: d09cc775
    [   96.510125] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4382 after call skb_clone(skb, GFP_ATOMIC) clone(skb): 6bbabfec, clone->sk:   (null)
    [   96.523690] skbuff: @jie.han net/core/skbuff.c, skb_clone_sk, 4387 assign sk: d09cc775 to clone->sk: d09cc775
    [   96.533970] @jie.han net/core/timestamping.c, skb_clone_tx_timestamp, 83 clone->sk: d09cc775
    [   96.542794] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2075 ptp_priv->tx_type: HWTSTAMP_TX_ON
    [   96.553095] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2079 skb: 6bbabfec, skb->sk: d09cc775, skb->sk->sk_flags: 0x800100, tx_flags: 0x1
    [   96.567161] @jie.han drivers/net/phy/motorcomm.c, parsing_ptp_msgtype_seqid, 1999 msgtype: SYNC, seq_id: 2
    [   96.577185] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2101 before call skb_queue_tail(&ptp_priv->tx_queue, skb); skb->sk: d09cc775
    [   96.590834] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2103 skb->sk->sk_flags: 0x800100
    [   96.600597] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_txtstamp, 2107 skb->sk->sk_refcnt: 5
    ptp4l[96.612]: timed out while polling for tx timestamp[   96.615037] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_get_txtstamp, 739 yt_ptp_get_txtstamp_paged() ret: 0, capts->seq_id: 2, capts->msgtype: SYNC
    
    ptp4l[96.613]: @jie.han increasing tx_timestamp_timeout may co[   96.631539] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 762 scan ptp_priv->tx_queue, skb->sk: d09cc775
    rrect this issue, but it is likely caused by a driver bug
    ptp4l[   96.648688] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 764 skb->sk->sk_flags: 0x800100
    [96.613]: @jie.han fd: 14 errno: -6
    ptp4l[96.614]: port 1: send[   96.664153] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 770 skb->sk->sk_refcnt: 3
     sync failed
    ptp4l[96.615]: port 1: MASTER to FAULTY on FAULT_D[   96.679279] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 786 skb->sk->sk_flags: 0x800100
    ETECTED (FT_UNSPECIFIED)
    [   96.694756] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 808 matched, seqid: 2, msgtype: SYNC
    [   96.707704] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 811 matched, skb->sk: d09cc775
    [   96.717795] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 818 skb->sk->sk_flags: 0x800100
    [   96.728230] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 822 before call skb_complete_tx_timestamp() skb: 6bbabfec
    [   96.740795] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 825 before call skb_complete_tx_timestamp() skb->sk: d09cc775
    [   96.753595] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_match_txtstamp, 829 before call skb_complete_tx_timestamp() shhwtstamps->hwtstamp: 0xd234ccf96873c6b
    [   96.768382] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4461 skb->sk->sk_flags: 0x800100
    [   96.778478] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4473 assigned hwtstamps: 0xd234ccf96873c6b to skb then call __skb_complete_tx_timestamp(SCM_TSTAMP_SND)
    [   96.794756] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4475 sk->sk_refcnt: 4
    [   96.803909] skbuff: @jie.han net/core/skbuff.c, skb_complete_tx_timestamp, 4480 skb: 6bbabfec, skb->sk: d09cc775
    [   96.814476] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4424 skb enqueued(sock_queue_err_skb() called), tstamp: 946684870825776400, skb: 6bbabfec, skb->sk: d09cc775
    [   96.831357] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4428 skb->sk->sk_error_queue.qlen: 0x0
    [   96.842179] skbuff: @jie.han net/core/skbuff.c, __skb_complete_tx_timestamp, 4430 skb->sk->sk_flags: 0x800100
    [   96.852455] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4256 skb->sk->sk_flags: 0x800100
    [   96.861914] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4267 skb->sk:   (null)
    [   96.870743] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4269 sk: d09cc775
    [   96.878636] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4277 skb->sk->sk_flags: 0x800100
    [   96.888337] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4285 before call skb_queue_tail(&sk->sk_error_queue, skb) skb: 6bbabfec
    [   96.901305] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4289 before call skb_queue_tail(&sk->sk_error_queue, skb) skb->sk: d09cc775
    [   96.914549] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4296 sk->sk_flags: 0x800100
    [   96.923582] skbuff: @jie.han net/core/skbuff.c, sock_queue_err_skb, 4308 sk->sk_error_queue.qlen: 0x1 and call sk->sk_error_report(sk)
    [   96.936036] sock: @jie.han net/core/sock.c, sock_def_error_report, 2701 wake up poll.
    [   96.944238] @jie.han drivers/net/phy/motorcomm.c, yt8011_ptp_do_aux_work, 893 reschedule: false
    ptp4l[96.970]: waiting 2^{4} seconds to clear fault on port 1
    ^Croot@am335x-evm:~/phy_ptp#
    
    motorcomm(29).c

  • Hi,

    Couple things.

    1. Why rely on the timestamping features in the PHY, IEEE1588-2008 (old name still sometimes used is v2) and IEEE802.1AS has been supported in upstream Linux on AM335x for 10 years or so. Why try to use the feature from the PHY instead.

    2. The kernel is old (6-7 years old), as a general recommendation first thing to try is move to more recent kernel. Are you sure the Motorcomm PHY driver has been tested with such an old kernel.

    3. Debugging a PHY driver for a non TI PHY is not something we can support. This looks like some backporting to an old kernel.

    4. Rather than copy pasting code, please point to the open source driver. On some Google searches I can see Motorcomm YT8521 being upstreamed in kernel version 5 years newer than 4.19, but that is probably not the PHY you are talking about.