Latest Linux kernel has supported getting PHC from bond directly. This
would help topology like VLAN over bond to get PHC natively. To achieve
this, the new hwtstamp flag is needed when passing hwtstamp_config to
kernel. Let's supply the flag first, and fall back without flag if user
runs on old kernel.

Split port_change_phc() from function port_link_status() so the event
functions could call it directly when find the phc changed.

In clock_create(), try to get ts info first, if failed, try the old way.

Signed-off-by: Hangbin Liu <liuhang...@gmail.com>
---
v4: define HWTSTAMP_FLAG_BONDED_PHC_INDEX in missing.h
    remove unneeded net_tstamp header files
v3: remove ifdef in clock_create() and FD_RTNL event.
v2: remove link state PHC_INDEX_CHANGED and use TS_LABEL_CHANGED only.
---
 clock.c        | 17 +++++++++---
 e2e_tc.c       |  7 ++++-
 missing.h      |  6 ++++
 p2p_tc.c       |  7 ++++-
 port.c         | 74 +++++++++++++++++++++++++++++++-------------------
 port_private.h |  1 +
 sk.c           |  5 ++++
 7 files changed, 83 insertions(+), 34 deletions(-)

diff --git a/clock.c b/clock.c
index 07bf582..6a8fbb5 100644
--- a/clock.c
+++ b/clock.c
@@ -1001,10 +1001,16 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
        c->timestamping = timestamping;
        required_modes = clock_required_modes(c);
        STAILQ_FOREACH(iface, &config->interfaces, list) {
-               memset(ts_label, 0, sizeof(ts_label));
-               if (!rtnl_get_ts_device(interface_name(iface), ts_label))
-                       interface_set_label(iface, ts_label);
-               interface_get_tsinfo(iface);
+               /* try find lowerlay device if we can't get iface tsinfo 
directly */
+               if (interface_get_tsinfo(iface) ||
+                   (interface_tsinfo_valid(iface) &&
+                    !interface_tsmodes_supported(iface, required_modes))) {
+                       memset(ts_label, 0, sizeof(ts_label));
+                       if (!rtnl_get_ts_device(interface_name(iface), 
ts_label))
+                               interface_set_label(iface, ts_label);
+                       interface_get_tsinfo(iface);
+               }
+
                if (interface_tsinfo_valid(iface) &&
                    !interface_tsmodes_supported(iface, required_modes)) {
                        pr_err("interface '%s' does not support requested 
timestamping mode",
@@ -1762,6 +1768,9 @@ int clock_switch_phc(struct clock *c, int phc_index)
        c->clkid = clkid;
        c->servo = servo;
        c->servo_state = SERVO_UNLOCKED;
+
+       pr_info("Switched to /dev/ptp%d as PTP clock", phc_index);
+
        return 0;
 }
 
diff --git a/e2e_tc.c b/e2e_tc.c
index 2f8e821..42baea3 100644
--- a/e2e_tc.c
+++ b/e2e_tc.c
@@ -123,7 +123,12 @@ enum fsm_event e2e_event(struct port *p, int fd_index)
 
        case FD_RTNL:
                pr_debug("%s: received link status notification", p->log_name);
-               rtnl_link_status(fd, p->name, port_link_status, p);
+               if (!interface_get_tsinfo(p->iface) &&
+                   (p->phc_index != interface_phc_index(p->iface)))
+                       port_change_phc(p);
+               else
+                       rtnl_link_status(fd, p->name, port_link_status, p);
+
                if (p->link_status == (LINK_UP|LINK_STATE_CHANGED)) {
                        return EV_FAULT_CLEARED;
                } else if ((p->link_status == (LINK_DOWN|LINK_STATE_CHANGED)) ||
diff --git a/missing.h b/missing.h
index 89cb513..e60c471 100644
--- a/missing.h
+++ b/missing.h
@@ -62,6 +62,12 @@ enum {
 };
 #endif
 
+#ifndef HWTSTAMP_FLAG_BONDED_PHC_INDEX
+enum {
+       HWTSTAMP_FLAG_BONDED_PHC_INDEX = (1<<0),
+};
+#endif
+
 #ifdef PTP_EXTTS_REQUEST2
 #define PTP_EXTTS_REQUEST_FAILED "PTP_EXTTS_REQUEST2 failed: %m"
 #else
diff --git a/p2p_tc.c b/p2p_tc.c
index 75cb3b9..1164c9a 100644
--- a/p2p_tc.c
+++ b/p2p_tc.c
@@ -126,7 +126,12 @@ enum fsm_event p2p_event(struct port *p, int fd_index)
 
        case FD_RTNL:
                pr_debug("%s: received link status notification", p->log_name);
-               rtnl_link_status(fd, p->name, port_link_status, p);
+               if (!interface_get_tsinfo(p->iface) &&
+                   (p->phc_index != interface_phc_index(p->iface)))
+                       port_change_phc(p);
+               else
+                       rtnl_link_status(fd, p->name, port_link_status, p);
+
                if (p->link_status == (LINK_UP|LINK_STATE_CHANGED)) {
                        return EV_FAULT_CLEARED;
                } else if ((p->link_status == (LINK_DOWN|LINK_STATE_CHANGED)) ||
diff --git a/port.c b/port.c
index 7e51e77..d5df8f9 100644
--- a/port.c
+++ b/port.c
@@ -2568,10 +2568,48 @@ static void bc_dispatch(struct port *p, enum fsm_event 
event, int mdiff)
        }
 }
 
+void port_change_phc(struct port *p)
+{
+       int required_modes;
+
+       /* Only switch phc with HW time stamping mode */
+       if (!interface_tsinfo_valid(p->iface) ||
+           interface_phc_index(p->iface) < 0)
+               return;
+
+       required_modes = clock_required_modes(p->clock);
+       if (!interface_tsmodes_supported(p->iface, required_modes)) {
+               pr_err("interface '%s' does not support requested "
+                      "timestamping mode, set link status down by force.",
+                      interface_label(p->iface));
+               p->link_status = LINK_DOWN | LINK_STATE_CHANGED;
+       } else if (p->phc_from_cmdline) {
+               pr_warning("%s: taking /dev/ptp%d from the "
+                          "command line, not the attached ptp%d",
+                          p->log_name, p->phc_index,
+                          interface_phc_index(p->iface));
+       } else if (p->phc_index != interface_phc_index(p->iface)) {
+               p->phc_index = interface_phc_index(p->iface);
+
+               if (clock_switch_phc(p->clock, p->phc_index)) {
+                       p->last_fault_type = FT_SWITCH_PHC;
+                       port_dispatch(p, EV_FAULT_DETECTED, 0);
+                       return;
+               }
+               clock_sync_interval(p->clock, p->log_sync_interval);
+
+               /* Ensure TS_LABEL_CHANGED is set for failover when
+                * PHC changed as we may not call port_change_phc()
+                * from port_link_status().
+                */
+               p->link_status |= TS_LABEL_CHANGED;
+       }
+}
+
 void port_link_status(void *ctx, int linkup, int ts_index)
 {
        char ts_label[MAX_IFNAME_SIZE + 1] = {0};
-       int link_state, required_modes;
+       int link_state;
        const char *old_ts_label;
        struct port *p = ctx;
 
@@ -2595,32 +2633,7 @@ void port_link_status(void *ctx, int linkup, int 
ts_index)
        if (p->link_status & LINK_UP &&
            (p->link_status & LINK_STATE_CHANGED || p->link_status & 
TS_LABEL_CHANGED)) {
                interface_get_tsinfo(p->iface);
-
-               /* Only switch phc with HW time stamping mode */
-               if (interface_tsinfo_valid(p->iface) &&
-                   interface_phc_index(p->iface) >= 0) {
-                       required_modes = clock_required_modes(p->clock);
-                       if (!interface_tsmodes_supported(p->iface, 
required_modes)) {
-                               pr_err("interface '%s' does not support 
requested "
-                                      "timestamping mode, set link status down 
by force.",
-                                      interface_label(p->iface));
-                               p->link_status = LINK_DOWN | LINK_STATE_CHANGED;
-                       } else if (p->phc_from_cmdline) {
-                               pr_warning("%s: taking /dev/ptp%d from the "
-                                          "command line, not the attached 
ptp%d",
-                                          p->log_name, p->phc_index,
-                                          interface_phc_index(p->iface));
-                       } else if (p->phc_index != 
interface_phc_index(p->iface)) {
-                               p->phc_index = interface_phc_index(p->iface);
-
-                               if (clock_switch_phc(p->clock, p->phc_index)) {
-                                       p->last_fault_type = FT_SWITCH_PHC;
-                                       port_dispatch(p, EV_FAULT_DETECTED, 0);
-                                       return;
-                               }
-                               clock_sync_interval(p->clock, 
p->log_sync_interval);
-                       }
-               }
+               port_change_phc(p);
        }
 
        /*
@@ -2722,7 +2735,12 @@ static enum fsm_event bc_event(struct port *p, int 
fd_index)
 
        case FD_RTNL:
                pr_debug("%s: received link status notification", p->log_name);
-               rtnl_link_status(fd, p->name, port_link_status, p);
+               if (!interface_get_tsinfo(p->iface) &&
+                   (p->phc_index != interface_phc_index(p->iface)))
+                       port_change_phc(p);
+               else
+                       rtnl_link_status(fd, p->name, port_link_status, p);
+
                if (p->link_status == (LINK_UP | LINK_STATE_CHANGED))
                        return EV_FAULT_CLEARED;
                else if ((p->link_status == (LINK_DOWN | LINK_STATE_CHANGED)) ||
diff --git a/port_private.h b/port_private.h
index 19eb944..4ef1c91 100644
--- a/port_private.h
+++ b/port_private.h
@@ -178,6 +178,7 @@ int port_delay_request(struct port *p);
 void port_disable(struct port *p);
 int port_initialize(struct port *p);
 int port_is_enabled(struct port *p);
+void port_change_phc(struct port *p);
 void port_link_status(void *ctx, int index, int linkup);
 int port_set_announce_tmo(struct port *p);
 int port_set_delay_tmo(struct port *p);
diff --git a/sk.c b/sk.c
index 8be0708..5bb065c 100644
--- a/sk.c
+++ b/sk.c
@@ -66,6 +66,11 @@ static int hwts_init(int fd, const char *device, int 
rx_filter,
 
        init_ifreq(&ifreq, &cfg, device);
 
+       cfg.flags = HWTSTAMP_FLAG_BONDED_PHC_INDEX;
+       /* Fall back without flag if user run new build on old kernel */
+       if (ioctl(fd, SIOCGHWTSTAMP, &ifreq) == -EINVAL)
+               init_ifreq(&ifreq, &cfg, device);
+
        switch (sk_hwts_filter_mode) {
        case HWTS_FILTER_CHECK:
                err = ioctl(fd, SIOCGHWTSTAMP, &ifreq);
-- 
2.31.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to