Netdev List
 help / color / mirror / Atom feed
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

[ ... ]

      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