Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ concurrency:
env:
DKMS_PKG: netdevsim
DKMS_VER: "6.9.5"
PTP_REPO: https://github.com/k8snetworkplumbingwg/ptp-operator.git
PTP_BRANCH: main
PTP_REPO: https://github.com/bnshr/ptp-operator.git
PTP_BRANCH: integrate-add-gnss

jobs:
# ------------------------------------------------------------------
Expand Down
196 changes: 151 additions & 45 deletions netdevsim/dpll.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ static ssize_t nsim_dpll_lock_status_store(struct kobject *kobj,

#define UBX_CFG_VALSET_HDR_LEN 4
#define UBX_CFGKEY_INFIL_NCNOTHRS 0x201100aa
/* CFG-MSGOUT group (bits 23:16 of the 32-bit key). linuxptp-daemon enables
* periodic NAV-STATUS/NAV-CLOCK via CFG-VALSET CFG-MSGOUT-UBX_NAV_* keys
* rather than classic CFG-MSG. */
#define UBX_CFG_GROUP_MSGOUT 0x91
/* Item IDs for UBX-NAV-STATUS on I2C/UART1/UART2/USB/SPI (0x2091001a..1e) */
#define UBX_MSGOUT_NAV_STATUS_FIRST 0x001a
#define UBX_MSGOUT_NAV_STATUS_LAST 0x001e
/* Item IDs for UBX-NAV-CLOCK on I2C/UART1/UART2/USB/SPI (0x20910065..69) */
#define UBX_MSGOUT_NAV_CLOCK_FIRST 0x0065
#define UBX_MSGOUT_NAV_CLOCK_LAST 0x0069

#define UBX_NAV_STATUS_LEN 16
#define UBX_NAV_CLOCK_LEN 20
Expand Down Expand Up @@ -422,6 +432,43 @@ static u8 nsim_gga_quality_to_gps_fix(u8 gga_quality)
* concatenated NMEA sentences from a single write() call, so we
* search for '$' start markers rather than only checking buf[0].
*/
/*
* Mirror GGA-derived gpsFix into DPLL lock_status so gnss-sim signal
* loss (NMEA fix quality 0) drives the same holdover path as UBX
* INFIL_NCNOTHRS:
* locked + gpsFix < 2 → HOLDOVER
* gpsFix >= 2 → LOCKED_HO_ACQ
* Do not promote UNLOCKED (sysfs freerun after holdover timeout) back
* to HOLDOVER while GGA remains invalid.
*/
static void nsim_dpll_apply_gps_fix(struct nsim_dpll *ndpll, u8 gps_fix)
{
enum dpll_lock_status new_status;

if (gps_fix != ndpll->gnss_gps_fix)
ndpll->gnss_gps_fix = gps_fix;

if (ndpll->signal_blocked)
return;

if (gps_fix < 2) {
if (ndpll->lock_status != DPLL_LOCK_STATUS_LOCKED_HO_ACQ)
return;
new_status = DPLL_LOCK_STATUS_HOLDOVER;
} else {
new_status = DPLL_LOCK_STATUS_LOCKED_HO_ACQ;
}

if (new_status == ndpll->lock_status)
return;

ndpll->lock_status = new_status;
pr_info("netdevsim: GGA gpsFix=%u → DPLL %s\n", gps_fix,
(new_status == DPLL_LOCK_STATUS_HOLDOVER) ? "holdover"
: "locked");
schedule_work(&ndpll->ntf_work);
}

static void nsim_parse_gga_fix(struct nsim_dpll *ndpll,
const unsigned char *buf, size_t count)
{
Expand All @@ -447,9 +494,10 @@ static void nsim_parse_gga_fix(struct nsim_dpll *ndpll,
if (i + 1 < count &&
buf[i + 1] >= '0' &&
buf[i + 1] <= '9') {
ndpll->gnss_gps_fix =
nsim_dpll_apply_gps_fix(
ndpll,
nsim_gga_quality_to_gps_fix(
buf[i + 1] - '0');
buf[i + 1] - '0'));
}
return;
}
Expand All @@ -476,6 +524,38 @@ static void nsim_gnss_close(struct gnss_device *gdev)
}
}

/* Start the 1 Hz NAV-STATUS/NAV-CLOCK emitter if not already running. */
static void nsim_ubx_enable_nav_timer(struct nsim_dpll *ndpll)
{
if (ndpll->ubx_nav_enabled)
return;

ndpll->ubx_nav_enabled = true;
hrtimer_start(&ndpll->ubx_timer, ns_to_ktime(NSEC_PER_SEC),
HRTIMER_MODE_REL);
pr_info("netdevsim: UBX NAV-STATUS/NAV-CLOCK timer enabled\n");
}

/* True if key is CFG-MSGOUT-UBX_NAV_{STATUS,CLOCK}_* with a non-zero rate. */
static bool nsim_ubx_cfgkey_enables_nav(u32 key, u8 val)
{
u8 group = (key >> 16) & 0xff;
u16 item = key & 0xffff;

if (group != UBX_CFG_GROUP_MSGOUT || val == 0)
return false;

if (item >= UBX_MSGOUT_NAV_STATUS_FIRST &&
item <= UBX_MSGOUT_NAV_STATUS_LAST)
return true;

if (item >= UBX_MSGOUT_NAV_CLOCK_FIRST &&
item <= UBX_MSGOUT_NAV_CLOCK_LAST)
return true;

return false;
}

static int nsim_gnss_write_raw(struct gnss_device *gdev,
const unsigned char *buf, size_t count)
{
Expand All @@ -499,23 +579,13 @@ static int nsim_gnss_write_raw(struct gnss_device *gdev,
return count;
}

// #region agent log
pr_info("netdevsim: d753ad gnss_write_raw: count=%zu first=0x%02x signal_blocked=%d\n",
count, buf[0], ndpll->signal_blocked);
// #endregion

/* UBX frame: sync(2) + class(1) + id(1) + len(2) minimum */
if (count < UBX_HDR_LEN || buf[0] != UBX_SYNC1 || buf[1] != UBX_SYNC2)
return count;

cls = buf[2];
id = buf[3];

// #region agent log
pr_info("netdevsim: d753ad UBX frame: cls=0x%02x id=0x%02x count=%zu\n",
cls, id, count);
// #endregion

switch (cls) {
case UBX_CLASS_MON:
if (id == UBX_MON_VER) {
Expand All @@ -531,14 +601,8 @@ static int nsim_gnss_write_raw(struct gnss_device *gdev,

if (msg_cls == UBX_CLASS_NAV &&
(msg_id == UBX_NAV_STATUS ||
msg_id == UBX_NAV_CLOCK)) {
if (!ndpll->ubx_nav_enabled) {
ndpll->ubx_nav_enabled = true;
hrtimer_start(&ndpll->ubx_timer,
ns_to_ktime(NSEC_PER_SEC),
HRTIMER_MODE_REL);
}
}
msg_id == UBX_NAV_CLOCK))
nsim_ubx_enable_nav_timer(ndpll);

len = ubx_build_ack(resp, sizeof(resp), cls, id);
if (len > 0)
Expand All @@ -549,41 +613,38 @@ static int nsim_gnss_write_raw(struct gnss_device *gdev,
size_t kv_end = count - UBX_CK_LEN;
size_t pos = UBX_HDR_LEN + UBX_CFG_VALSET_HDR_LEN;

// #region agent log
pr_info("netdevsim: d753ad CFG-VALSET: payload_start=%zu kv_end=%zu\n",
pos, kv_end);
// #endregion
while (pos + 4 < kv_end) {
/* Key/value pairs are U1-sized for the keys we handle
* (CFG-MSGOUT rates and INFIL_NCNOTHRS). */
while (pos + 5 <= kv_end) {
u32 key = kv[0] | (kv[1] << 8) |
(kv[2] << 16) | (kv[3] << 24);
kv += 4;
pos += 4;
u8 val = kv[4];

// #region agent log
pr_info("netdevsim: d753ad CFG-VALSET key=0x%08x pos=%zu expect=0x%08x\n",
key, pos, UBX_CFGKEY_INFIL_NCNOTHRS);
// #endregion
if (key == UBX_CFGKEY_INFIL_NCNOTHRS && pos < kv_end) {
u8 val = *kv;
kv += 5;
pos += 5;

if (nsim_ubx_cfgkey_enables_nav(key, val)) {
nsim_ubx_enable_nav_timer(ndpll);
continue;
}

if (key == UBX_CFGKEY_INFIL_NCNOTHRS) {
if (val > 0) {
ndpll->signal_blocked = true;
ndpll->gnss_gps_fix = 0x00;
ndpll->lock_status = DPLL_LOCK_STATUS_HOLDOVER;
pr_info("netdevsim: UBX CFG-VALSET INFIL_NCNOTHRS=%u → signal blocked, holdover\n", val);
ndpll->lock_status =
DPLL_LOCK_STATUS_HOLDOVER;
pr_info("netdevsim: UBX CFG-VALSET INFIL_NCNOTHRS=%u → signal blocked, holdover\n",
val);
} else {
ndpll->signal_blocked = false;
ndpll->gnss_gps_fix = 0x03;
ndpll->lock_status = DPLL_LOCK_STATUS_LOCKED_HO_ACQ;
ndpll->signal_blocked = false;
ndpll->gnss_gps_fix = 0x03;
ndpll->lock_status =
DPLL_LOCK_STATUS_LOCKED_HO_ACQ;
pr_info("netdevsim: UBX CFG-VALSET INFIL_NCNOTHRS=0 → signal restored, locked\n");
}
schedule_work(&ndpll->ntf_work);
kv++;
pos++;
break;
}
kv++;
pos++;
}

len = ubx_build_ack(resp, sizeof(resp), cls, id);
Expand Down Expand Up @@ -683,7 +744,10 @@ int nsim_dpll_init(struct nsim_dev *nsim_dev)
if (err)
goto err_eec_put;

/* GNSS input pin on PPS DPLL */
/* GNSS input pin on both EEC and PPS DPLLs (matches real E810 behavior).
* linuxptp-daemon expects pin.ParentDevice to have entries at both
* index 0 (EEC) and index 1 (PPS) — the phase offset is read from
* ParentDevice[PPS_PIN_INDEX=1].PhaseOffset. */
ndpll->gnss_pin_priv.direction = DPLL_PIN_DIRECTION_INPUT;
ndpll->gnss_pin_priv.frequency = DPLL_PIN_FREQUENCY_1_HZ;

Expand All @@ -695,12 +759,18 @@ int nsim_dpll_init(struct nsim_dev *nsim_dev)
goto err_eec_unreg;
}

err = dpll_pin_register(ndpll->pps_dpll, ndpll->gnss_pin,
err = dpll_pin_register(ndpll->eec_dpll, ndpll->gnss_pin,
&nsim_dpll_gnss_pin_ops,
&ndpll->gnss_pin_priv);
if (err)
goto err_gnss_put;

err = dpll_pin_register(ndpll->pps_dpll, ndpll->gnss_pin,
&nsim_dpll_gnss_pin_ops,
&ndpll->gnss_pin_priv);
if (err)
goto err_gnss_unreg_eec;

/* E810-compatible external pins (SMA1, SMA2, U.FL1, U.FL2) */
{
int i;
Expand Down Expand Up @@ -729,10 +799,21 @@ int nsim_dpll_init(struct nsim_dev *nsim_dev)
ndpll->ext_pin_privs[i].frequency =
DPLL_PIN_FREQUENCY_1_HZ;

err = dpll_pin_register(ndpll->eec_dpll, epin,
&nsim_dpll_gnss_pin_ops,
&ndpll->ext_pin_privs[i]);
if (err) {
dpll_pin_put(epin);
goto err_ext_cleanup;
}

err = dpll_pin_register(ndpll->pps_dpll, epin,
&nsim_dpll_gnss_pin_ops,
&ndpll->ext_pin_privs[i]);
if (err) {
dpll_pin_unregister(ndpll->eec_dpll, epin,
&nsim_dpll_gnss_pin_ops,
&ndpll->ext_pin_privs[i]);
dpll_pin_put(epin);
goto err_ext_cleanup;
}
Expand Down Expand Up @@ -796,9 +877,19 @@ int nsim_dpll_init(struct nsim_dev *nsim_dev)
goto err_ports_cleanup;
}

err = dpll_pin_register(ndpll->eec_dpll, pin,
&nsim_dpll_rclk_pin_ops, npin);
if (err) {
dpll_pin_put(pin);
kfree(npin);
goto err_ports_cleanup;
}

err = dpll_pin_register(ndpll->pps_dpll, pin,
&nsim_dpll_rclk_pin_ops, npin);
if (err) {
dpll_pin_unregister(ndpll->eec_dpll, pin,
&nsim_dpll_rclk_pin_ops, npin);
dpll_pin_put(pin);
kfree(npin);
goto err_ports_cleanup;
Expand Down Expand Up @@ -933,12 +1024,19 @@ int nsim_dpll_init(struct nsim_dev *nsim_dev)
ndpll->ext_pins[i],
&nsim_dpll_gnss_pin_ops,
&ndpll->ext_pin_privs[i]);
dpll_pin_unregister(ndpll->eec_dpll,
ndpll->ext_pins[i],
&nsim_dpll_gnss_pin_ops,
&ndpll->ext_pin_privs[i]);
dpll_pin_put(ndpll->ext_pins[i]);
}
ndpll->num_ext_pins = 0;
}
dpll_pin_unregister(ndpll->pps_dpll, ndpll->gnss_pin,
&nsim_dpll_gnss_pin_ops, &ndpll->gnss_pin_priv);
err_gnss_unreg_eec:
dpll_pin_unregister(ndpll->eec_dpll, ndpll->gnss_pin,
&nsim_dpll_gnss_pin_ops, &ndpll->gnss_pin_priv);
err_gnss_put:
dpll_pin_put(ndpll->gnss_pin);
err_eec_unreg:
Expand All @@ -962,6 +1060,8 @@ static void nsim_dpll_cleanup_port_pins(struct nsim_dpll *ndpll)
dpll_netdev_pin_clear(npin->ns->netdev);
dpll_pin_unregister(ndpll->pps_dpll, npin->pin,
&nsim_dpll_rclk_pin_ops, npin);
dpll_pin_unregister(ndpll->eec_dpll, npin->pin,
&nsim_dpll_rclk_pin_ops, npin);
dpll_pin_put(npin->pin);
list_del(&npin->list);
kfree(npin);
Expand Down Expand Up @@ -1002,13 +1102,19 @@ void nsim_dpll_exit(struct nsim_dev *nsim_dev)
ndpll->ext_pins[i],
&nsim_dpll_gnss_pin_ops,
&ndpll->ext_pin_privs[i]);
dpll_pin_unregister(ndpll->eec_dpll,
ndpll->ext_pins[i],
&nsim_dpll_gnss_pin_ops,
&ndpll->ext_pin_privs[i]);
dpll_pin_put(ndpll->ext_pins[i]);
}
ndpll->num_ext_pins = 0;
}

dpll_pin_unregister(ndpll->pps_dpll, ndpll->gnss_pin,
&nsim_dpll_gnss_pin_ops, &ndpll->gnss_pin_priv);
dpll_pin_unregister(ndpll->eec_dpll, ndpll->gnss_pin,
&nsim_dpll_gnss_pin_ops, &ndpll->gnss_pin_priv);
dpll_pin_put(ndpll->gnss_pin);

dpll_device_unregister(ndpll->eec_dpll, &nsim_dpll_device_ops, ndpll);
Expand Down
Loading