dpll: zl3073x: do not offer 0 Hz as a supported pin frequency

zl3073x_pin_props_get() always adds the current pin frequency to the
supported list without checking it. A sub-Hz frequency reads back as
0 Hz, so 0 Hz can then be requested and the output frequency set
callback divides by zero. A 0 Hz entry in the firmware node is not
rejected either: it is offered for an input pin, and for an output pin
zl3073x_pin_check_freq() divides by it at probe time.

Do not add a 0 Hz current frequency and reject 0 Hz in
zl3073x_pin_check_freq(). If the list ends up empty, do not publish it
at all, as the DPLL core rejects an empty non-NULL list.

Found by code inspection, not triggered at runtime.

Fixes: 85a9aaac4a ("dpll: zl3073x: Include current frequency in supported frequencies list")
Reviewed-by: Petr Oros <poros@redhat.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Fixes: a99a9f0ebd ("dpll: zl3073x: Read DPLL types and pin properties from system firmware")
Link: https://patch.msgid.link/20261011061211.448373-2-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Ivan Vecera 2026-10-11 08:12:07 +02:00 committed by Jakub Kicinski
parent f42d67a504
commit 23171065fb

View File

@ -30,7 +30,7 @@ static bool
zl3073x_pin_check_freq(struct zl3073x_dev *zldev, enum dpll_pin_direction dir,
u8 id, u64 freq)
{
if (freq > U32_MAX)
if (!freq || freq > U32_MAX)
goto err_inv_freq;
if (dir == DPLL_PIN_DIRECTION_INPUT) {
@ -295,13 +295,20 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
goto err_alloc_ranges;
}
/* Start with current frequency at index 0 */
ranges[0] = (struct dpll_pin_frequency)DPLL_PIN_FREQUENCY(curr_freq);
/* Start with current frequency at index 0. A sub-Hz frequency is
* read back as 0 Hz and cannot be set, so it is not offered.
*/
j = 0;
if (curr_freq) {
struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(curr_freq);
ranges[j++] = freq;
}
/* Add frequencies from firmware node, skipping current frequency
* and filtering out frequencies not representable by device
*/
for (i = 0, j = 1; i < num_freqs; i++) {
for (i = 0; i < num_freqs; i++) {
struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]);
if (freqs[i] == curr_freq)
@ -312,6 +319,14 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
}
}
/* The DPLL core rejects a non-NULL list without entries, so do
* not publish the array at all when nothing is settable.
*/
if (!j) {
kfree(ranges);
ranges = NULL;
}
/* Save number of freq ranges and pointer to them into pin properties */
props->dpll_props.freq_supported = ranges;
props->dpll_props.freq_supported_num = j;