From: Jakub Kicinski <kuba@kernel.org>
To: ivecera@redhat.com
Cc: Jakub Kicinski <kuba@kernel.org>,
netdev@vger.kernel.org, poros@redhat.com,
arkadiusz.kubalewski@intel.com, davem@davemloft.net,
donald.hunter@gmail.com, edumazet@google.com, jiri@resnulli.us,
mschmidt@redhat.com, pabeni@redhat.com, pvaanane@redhat.com,
Prathosh.Satish@microchip.com, horms@kernel.org,
vadim.fedorenko@linux.dev, linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v3 2/2] dpll: zl3073x: add NCO virtual input pin
Date: Fri, 22 May 2026 17:27:42 -0700 [thread overview]
Message-ID: <20260523002742.1766902-1-kuba@kernel.org> (raw)
In-Reply-To: <20260521074220.432590-3-ivecera@redhat.com>
This is an AI-generated review of your patch. The human sending this
email says "I think the report / question about the SEM wasn't asked
on v2?"
---
dpll: zl3073x: add NCO virtual input pin
This change adds a virtual NCO input pin that lets userspace switch a
DPLL channel into NCO mode, and registers it with the new
DPLL_PIN_TYPE_INT_NCO type. It also rearranges chan->df_offset
handling so it is only read when the DPLL is locked, and adds a
ZL_REG_DPLL_CTRL register cache plus state_set support.
> diff --git a/drivers/dpll/zl3073x/chan.c b/drivers/dpll/zl3073x/chan.c
> index 2fe3c3da84bb..f5d6c7917e57 100644
> --- a/drivers/dpll/zl3073x/chan.c
> +++ b/drivers/dpll/zl3073x/chan.c
> @@ -21,6 +21,11 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
> u64 val;
> int rc;
>
> + /* Serialize with zl3073x_chan_nco_mode_set() which also
> + * modifies chan->mode_refsel and chan->df_offset.
> + */
> + guard(mutex)(&zldev->multiop_lock);
> +
> rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index),
> &chan->mon_status);
> if (rc)
> @@ -31,7 +36,10 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
> if (rc)
> return rc;
>
> - /* Read df_offset vs tracked reference */
> + /* Read df_offset only when locked to a reference */
> + if (zl3073x_chan_lock_state_get(chan) != ZL_DPLL_MON_STATUS_STATE_LOCK)
> + return 0;
> +
[Medium]
With this early return, when the DPLL boots in NCO mode and
zl3073x_chan_state_fetch() calls zl3073x_chan_state_update(),
chan->df_offset is left at the kzalloc-zeroed 0 (NCO mode is not
ZL_DPLL_MON_STATUS_STATE_LOCK).
zl3073x_dpll_nco_pin_register() then calls zl3073x_chan_state_set() to
update the ctrl bits, but state_set() never reads
ZL_REG_DPLL_DF_OFFSET. The only place that populates df_offset in NCO
mode is zl3073x_chan_nco_mode_set(), which only runs on a userspace
CONNECTED transition for the NCO pin.
Does this leave zl3073x_dpll_nco_pin_ffo_get() reporting ffo=0 forever
on a system that boots already in NCO mode, until userspace explicitly
disconnects and reconnects the NCO pin?
The commit message says:
The value is static for the duration of NCO mode and serves as the
FFO snapshot reported to userspace.
Does that statement still hold for the boot-in-NCO-mode case?
> rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
> ZL_DPLL_DF_READ_SEM);
> if (rc)
> @@ -56,6 +64,50 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
> return 0;
> }
>
> +/**
> + * zl3073x_chan_nco_mode_set - switch DPLL channel to NCO mode
> + * @zldev: pointer to zl3073x_dev structure
> + * @index: DPLL channel index
> + *
> + * Switches the channel to NCO mode, waits for the hardware to
> + * auto-capture the tracking offset via nco_auto_read, then reads
> + * the captured df_offset directly from the register.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +int zl3073x_chan_nco_mode_set(struct zl3073x_dev *zldev, u8 index)
> +{
> + struct zl3073x_chan *chan = &zldev->chan[index];
> + u8 mode_refsel;
> + u64 val;
> + int rc;
> +
> + /* Serialize with zl3073x_chan_state_update() which also
> + * reads chan->df_offset from the same register.
> + */
> + guard(mutex)(&zldev->multiop_lock);
> +
> + mode_refsel = chan->mode_refsel;
> + FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_MODE, &mode_refsel,
> + ZL_DPLL_MODE_REFSEL_MODE_NCO);
> +
> + rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index),
> + mode_refsel);
> + if (rc)
> + return rc;
> +
> + chan->mode_refsel = mode_refsel;
> +
> + /* Best-effort read of df_offset captured by nco_auto_read.
> + * Mode switch already succeeded, so don't propagate a
> + * df_offset read failure back to userspace.
> + */
> + rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val);
> + chan->df_offset = !rc ? sign_extend64(val, 47) : 0;
> +
> + return 0;
> +}
[Medium]
Should this read use the same DF_READ semaphore handshake that
zl3073x_chan_state_update() uses for the same DF_OFFSET register?
The existing path does:
poll ZL_DPLL_DF_READ_SEM == 0
write ZL_DPLL_DF_READ_SEM | ZL_DPLL_DF_READ_REF_OFST
poll ZL_DPLL_DF_READ_SEM == 0
read ZL_REG_DPLL_DF_OFFSET
The new path writes MODE_REFSEL=NCO and then immediately reads the
48-bit DF_OFFSET register without any handshake.
The commit message says:
The nco_auto_read populates df_offset before the mode switch
completes so no delay is needed.
Is there a datasheet reference for this guarantee that could be cited
in the code comment?
If the auto-capture takes any non-zero amount of time after the
MODE_REFSEL bus write completes, can this read return stale REFLOCK-era
data or a torn value across the multi-byte 48-bit register? Combined
with the early return added to zl3073x_chan_state_update() for non-LOCK
states, would such a value persist for the entire NCO session?
[Medium]
There is also a question about reader synchronization for chan->df_offset.
zl3073x_chan_nco_mode_set() writes chan->df_offset under
zldev->multiop_lock. The periodic worker zl3073x_dpll_changes_check()
calls zl3073x_dpll_pin_ffo_check(), which reads chan->df_offset via
zl3073x_chan_df_offset_get() without holding multiop_lock:
static inline s64
zl3073x_chan_df_offset_get(const struct zl3073x_chan *chan)
{
return chan->df_offset;
}
Consider: DPLL is in REFLOCK with a pin locked, the worker has finished
zl3073x_chan_state_update() (released multiop_lock), is iterating pins,
and enters ffo_check just as a netlink connect of the NCO pin calls
zl3073x_chan_nco_mode_set() and overwrites chan->df_offset.
drivers/dpll/zl3073x/Kconfig has no 64BIT dependency, so on 32-bit
builds the s64 store is two 32-bit stores. Can the worker observe a
torn value, push it through atomic64_xchg into pin->freq_offset, and
emit a dpll_pin_change_ntf with that value?
Pre-patch, df_offset was only written from state_update() in the worker
context, so writer and reader were sequential. Should the ffo_check
reader take multiop_lock, or chan->df_offset be promoted to an
atomic64_t/READ_ONCE pair?
> +
> /**
> * zl3073x_chan_state_fetch - fetch DPLL channel state from hardware
> * @zldev: pointer to zl3073x_dev structure
[ ... ]
prev parent reply other threads:[~2026-05-23 0:27 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-21 7:42 [PATCH net-next v3 0/2] dpll: add NCO pin type and zl3073x support Ivan Vecera
2026-05-21 7:42 ` [PATCH net-next v3 1/2] dpll: add DPLL_PIN_TYPE_INT_NCO pin type Ivan Vecera
2026-05-21 7:42 ` [PATCH net-next v3 2/2] dpll: zl3073x: add NCO virtual input pin Ivan Vecera
2026-05-23 0:27 ` Jakub Kicinski [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260523002742.1766902-1-kuba@kernel.org \
--to=kuba@kernel.org \
--cc=Prathosh.Satish@microchip.com \
--cc=arkadiusz.kubalewski@intel.com \
--cc=davem@davemloft.net \
--cc=donald.hunter@gmail.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=ivecera@redhat.com \
--cc=jiri@resnulli.us \
--cc=linux-kernel@vger.kernel.org \
--cc=mschmidt@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=poros@redhat.com \
--cc=pvaanane@redhat.com \
--cc=vadim.fedorenko@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox