From: sashiko-bot@kernel.org
To: "Ali Rouhi" <arouhi@sitime.com>
Cc: conor+dt@kernel.org, devicetree@vger.kernel.org, robh@kernel.org
Subject: Re: [PATCH net-next v6 3/3] dpll: add SiTime SiT9531x DPLL clock driver
Date: Thu, 13 Aug 2026 17:56:01 +0000 [thread overview]
Message-ID: <20260813175601.D57C31F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260812175337.18155-4-arouhi@sitime.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] Use-After-Free of Pin Properties and Frequency Arrays
- [High] State Mismatch / Logic Flaw in Pin Getters
- [High] Destructive Priority Overwrite in Hardware Table
- [High] Use-After-Free on Probe Error Path Due to Missing DPLL Unregistration
- [Medium] Silent Failure on Manual Pin Connection Request
- [Medium] Missing SYSREF/SYNCB/Pulser Features
- [Medium] Hardware Routing Loop via INTSYNC
--
--- Patch [3]: [PATCH net-next v6 3/3] dpll: add SiTime SiT9531x DPLL clock driver ---
commit 841a91aff3f30b8a2e2bee8952633134d7bbdee2
Author: Ali Rouhi <arouhi@sitime.com>
Subject: dpll: add SiTime SiT9531x DPLL clock driver
Summary: This commit adds a DPLL subsystem driver for the SiTime SiT95316
and SiT95317 clock generators. It supports hardware state monitoring, priority
management, and frequency/phase configuration.
> - SYSREF/SYNCB/Pulser output mode control
[Severity: Medium]
Is this functionality fully exposed to userspace? The commit message mentions
support for SYSREF/SYNCB/Pulser modes, but looking at the driver,
sit9531x_output_pulse_ctrl_set() only appears to be called with a hardcoded
default during embedded sync setup. It looks like the other modes might not
be reachable.
> diff --git a/drivers/dpll/sit9531x/core.c b/drivers/dpll/sit9531x/core.c
> index 0000000000000..711ab16b0897a
> --- /dev/null
> +++ b/drivers/dpll/sit9531x/core.c
[ ... ]
> @@ -596,32 +596,25 @@ int sit9531x_input_prio_set(struct sit9531x_dev *sitdev, u8 pll_idx,
>
> usleep_range(10000, 12000);
>
> /*
> * Write the requested slot on Page 1, then fill the remaining
> * slots with the same source, matching the procedure script's
> * backfill behaviour.
> */
> for (slot = prio; slot < SIT9531X_PRIO_MAX_SLOTS; slot++) {
> reg = sit9531x_prio_reg(pll_idx, slot);
>
> rc = sit9531x_read_u8(sitdev, reg, &val);
> if (rc)
> goto commit;
>
> val = sit9531x_prio_slot_set(val, slot, input_idx);
[Severity: High]
Does this loop unintentionally wipe out fallback configurations? When userspace
sets a priority, this loop fills not only the requested slot but also all
lower-priority slots with the exact same input source. This appears to destroy
any other fallback inputs the user might have configured in the hardware table.
[ ... ]
> @@ -2496,25 +2496,15 @@ int sit9531x_dev_start(struct sit9531x_dev *sitdev)
> if (rc)
> return rc;
>
> list_for_each_entry(sitdpll, &sitdev->dplls, list) {
> rc = sit9531x_dpll_register(sitdpll);
> if (rc) {
> dev_err_probe(sitdev->dev, rc,
> "Failed to register DPLL%u\n",
> sitdpll->id);
> return rc;
> }
> }
[ ... ]
> @@ -2825,18 +2815,10 @@ static void sit9531x_dpll_list_free(struct sit9531x_dev *sitdev)
> {
> struct sit9531x_dpll *sitdpll, *next;
>
> list_for_each_entry_safe(sitdpll, next, &sitdev->dplls, list) {
> list_del(&sitdpll->list);
> sit9531x_dpll_free(sitdpll);
> }
> }
[Severity: High]
Could this error path leave the DPLL subsystem with dangling pointers? If
sit9531x_dpll_register() succeeds for the first DPLL but fails for the next,
sit9531x_dev_start() returns an error without unwinding the already
registered DPLLs. The error handler in sit9531x_devm_dpll_init() then calls
sit9531x_dpll_list_free() to free the backing memory directly, bypassing
dpll_device_unregister() and dpll_pin_unregister().
> diff --git a/drivers/dpll/sit9531x/dpll.c b/drivers/dpll/sit9531x/dpll.c
> index 0000000000000..364f870ac3041
> --- /dev/null
> +++ b/drivers/dpll/sit9531x/dpll.c
[ ... ]
> @@ -259,32 +259,25 @@ static int
> sit9531x_dpll_input_pin_state_on_dpll_get(const struct dpll_pin *pin,
> void *pin_priv,
> const struct dpll_device *dpll,
> void *dpll_priv,
> enum dpll_pin_state *state,
> struct netlink_ext_ack *extack)
> {
[ ... ]
> if (chan->locked && !chan->inner_lol &&
> chan->selected_ref == dpin->id)
> *state = DPLL_PIN_STATE_CONNECTED;
> /* In auto mode, enabled inputs with good signal are selectable */
> else if (!chan->mode && ref->enabled && !ref->los && !ref->oof)
> *state = DPLL_PIN_STATE_SELECTABLE;
> else
> *state = DPLL_PIN_STATE_DISCONNECTED;
[Severity: High]
Might this logic report an incorrect routing state? The ref->enabled flag
represents a global physical state for the pin. If DPLL A requests an input
and enables the receiver, DPLL B will also see ref->enabled as true and
report the pin as DPLL_PIN_STATE_SELECTABLE, even if that pin isn't in DPLL
B's priority table.
Additionally, if a signal is lost (ref->los becomes true), this drops the
state to DPLL_PIN_STATE_DISCONNECTED. Does the DPLL API expect degraded pins
to still show as logically connected or selectable rather than entirely
disconnected?
[ ... ]
> @@ -326,32 +319,25 @@ static int
> sit9531x_dpll_input_pin_state_on_dpll_set(const struct dpll_pin *pin,
> void *pin_priv,
> const struct dpll_device *dpll,
> void *dpll_priv,
> enum dpll_pin_state state,
> struct netlink_ext_ack *extack)
> {
[ ... ]
> switch (state) {
> case DPLL_PIN_STATE_DISCONNECTED:
> rc = sit9531x_input_prio_remove(sitdev, sitdpll->id, hw_src);
> if (rc)
> break;
> ref->pll_mask &= ~pll_bit;
> if (ref->pll_mask)
> rc = 0; /* another DPLL still uses this input */
> else
> rc = sit9531x_input_disable(sitdev, dpin->id);
> break;
> case DPLL_PIN_STATE_SELECTABLE:
> case DPLL_PIN_STATE_CONNECTED:
> rc = sit9531x_input_enable(sitdev, dpin->id);
> if (rc)
> break;
> rc = sit9531x_input_prio_add(sitdev, sitdpll->id, hw_src);
[Severity: Medium]
Should DPLL_PIN_STATE_CONNECTED enforce a manual lock here? It appears to
fall through to the exact same logic as DPLL_PIN_STATE_SELECTABLE, adding
the input to the priority table but leaving the hardware in automatic
selection mode instead of forcing a connection.
[ ... ]
> @@ -651,32 +637,25 @@ static int
> sit9531x_dpll_intsync_src_state_on_dpll_set(const struct dpll_pin *pin,
> void *pin_priv,
> const struct dpll_device *dpll,
> void *dpll_priv,
> enum dpll_pin_state state,
> struct netlink_ext_ack *extack)
> {
[ ... ]
> switch (state) {
> case DPLL_PIN_STATE_CONNECTED:
> if (sitdev->intsync_src == sitdpll->id)
> break;
> if (sitdev->intsync_src >= 0) {
> NL_SET_ERR_MSG(extack,
> "INTSYNC is already sourced by another PLL");
> rc = -EBUSY;
> break;
> }
> rc = sit9531x_intsync_enable(sitdev, sitdpll->id);
[Severity: Medium]
Is there a protection missing here against hardware routing loops? While the
destination getter correctly prevents adding INTSYNC to a PLL's priority
table if that PLL is already the source, this function doesn't seem to check
if the PLL already has INTSYNC as a destination before making it the source.
Could userspace configure a PLL to source from INTSYNC and then drive INTSYNC
with the same PLL?
> diff --git a/drivers/dpll/sit9531x/prop.c b/drivers/dpll/sit9531x/prop.c
> index 0000000000000..8a0105c8c6472
> --- /dev/null
> +++ b/drivers/dpll/sit9531x/prop.c
[ ... ]
> @@ -357,10 +357,8 @@ void sit9531x_pin_props_put(struct sit9531x_pin_props *props)
> {
> kfree(props->dpll_props.freq_supported);
>
> if (props->fwnode)
> fwnode_handle_put(props->fwnode);
>
> kfree(props);
> }
[Severity: Critical]
Will this lead to a use-after-free when userspace queries the pin properties?
The sit9531x_pin_props_get() function dynamically allocates both the props
structure and the freq_supported array. When passed into dpll_pin_get()
in sit9531x_dpll_pin_register(), the DPLL core retains those pointers.
Since sit9531x_pin_props_put() immediately frees these allocations on the
success path, it looks like the DPLL core might be left holding dangling
pointers.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260812175337.18155-1-arouhi@sitime.com?part=3
prev parent reply other threads:[~2026-08-13 17:56 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 17:55 [PATCH net-next v6 0/3] dpll: add SiTime SiT9531x DPLL clock driver Ali Rouhi
2026-08-12 17:55 ` [PATCH net-next v6 1/3] dt-bindings: vendor-prefixes: add SiTime Corporation Ali Rouhi
2026-08-12 17:55 ` [PATCH net-next v6 2/3] dt-bindings: dpll: add SiTime SiT95316 clock generator Ali Rouhi
2026-08-13 7:35 ` Krzysztof Kozlowski
2026-08-12 17:55 ` [PATCH net-next v6 3/3] dpll: add SiTime SiT9531x DPLL clock driver Ali Rouhi
2026-08-13 17:56 ` sashiko-bot [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=20260813175601.D57C31F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=arouhi@sitime.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.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