[PATCH iwl-net v7 2/3] ice: fix missing dpll notifications for SW pins
From: Petr Oros
Date: Fri Apr 17 2026 - 11:00:07 EST
The SMA/U.FL pin redesign (commit 2dd5d03c77e2 ("ice: redesign dpll
sma/u.fl pins control")) introduced software-controlled pins that wrap
backing CGU input/output pins, but never updated the notification and
data paths to propagate pin events to these SW wrappers.
The periodic work sends dpll_pin_change_ntf() only for direct CGU input
pins. SW pins that wrap these inputs never receive change or phase
offset notifications, so userspace consumers such as synce4l monitoring
SMA pins via dpll netlink never learn about state transitions or phase
offset updates. Similarly, ice_dpll_phase_offset_get() reads the SW
pin's own phase_offset field which is never updated; the PPS monitor
writes to the backing CGU input's field instead.
Fix by introducing ice_dpll_pin_ntf(), a wrapper around
dpll_pin_change_ntf() that also notifies any registered SMA/U.FL pin
whose backing CGU input matches. Replace all direct
dpll_pin_change_ntf() calls in the periodic notification paths with
this wrapper. Fix ice_dpll_phase_offset_get() to return the backing
CGU input's phase_offset for input-direction SW pins.
Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control")
Signed-off-by: Petr Oros <poros@xxxxxxxxxx>
---
drivers/net/ethernet/intel/ice/ice_dpll.c | 47 +++++++++++++++++------
1 file changed, 36 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 3a90a2940fdc6e..11b942b83500fb 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -1963,7 +1963,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
d->active_input == p->input->pin))
*phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
else if (d->phase_offset_monitor_period)
- *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
+ *phase_offset = (p->input &&
+ p->direction == DPLL_PIN_DIRECTION_INPUT ?
+ p->input->phase_offset :
+ p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR;
else
*phase_offset = 0;
mutex_unlock(&pf->dplls.lock);
@@ -2659,6 +2662,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
return pci_get_dsn(pf->pdev);
}
+/**
+ * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers
+ * @dplls: pointer to dplls struct
+ * @pin: the dpll_pin that changed
+ *
+ * Send a change notification for @pin and for any registered SMA/U.FL pin
+ * whose backing CGU input matches @pin.
+ */
+static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin)
+{
+ dpll_pin_change_ntf(pin);
+ for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) {
+ if (dplls->sma[i].pin && dplls->sma[i].input &&
+ dplls->sma[i].input->pin == pin)
+ dpll_pin_change_ntf(dplls->sma[i].pin);
+ if (dplls->ufl[i].pin && dplls->ufl[i].input &&
+ dplls->ufl[i].input->pin == pin)
+ dpll_pin_change_ntf(dplls->ufl[i].pin);
+ }
+}
+
/**
* ice_dpll_notify_changes - notify dpll subsystem about changes
* @d: pointer do dpll
@@ -2667,6 +2691,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
*/
static void ice_dpll_notify_changes(struct ice_dpll *d)
{
+ struct ice_dplls *dplls = &d->pf->dplls;
bool pin_notified = false;
if (d->prev_dpll_state != d->dpll_state) {
@@ -2675,17 +2700,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d)
}
if (d->prev_input != d->active_input) {
if (d->prev_input)
- dpll_pin_change_ntf(d->prev_input);
+ ice_dpll_pin_ntf(dplls, d->prev_input);
d->prev_input = d->active_input;
if (d->active_input) {
- dpll_pin_change_ntf(d->active_input);
+ ice_dpll_pin_ntf(dplls, d->active_input);
pin_notified = true;
}
}
if (d->prev_phase_offset != d->phase_offset) {
d->prev_phase_offset = d->phase_offset;
if (!pin_notified && d->active_input)
- dpll_pin_change_ntf(d->active_input);
+ ice_dpll_pin_ntf(dplls, d->active_input);
}
}
@@ -2714,6 +2739,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
/**
* ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes
+ * @dplls: pointer to dplls struct
* @pins: array of ice_dpll_pin pointers registered within dpll subsystem
* @pin_num: number of pins
* @phase_offset_ntf_mask: bitmask of pin indexes to notify
@@ -2723,15 +2749,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
*
* Context: Must be called while pf->dplls.lock is released.
*/
-static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins,
+static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls,
+ struct ice_dpll_pin *pins,
u8 pin_num,
u32 phase_offset_ntf_mask)
{
- int i = 0;
-
- for (i = 0; i < pin_num; i++)
- if (phase_offset_ntf_mask & (1 << i))
- dpll_pin_change_ntf(pins[i].pin);
+ for (int i = 0; i < pin_num; i++)
+ if (phase_offset_ntf_mask & BIT(i))
+ ice_dpll_pin_ntf(dplls, pins[i].pin);
}
/**
@@ -2907,7 +2932,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
ice_dpll_notify_changes(de);
ice_dpll_notify_changes(dp);
if (phase_offset_ntf)
- ice_dpll_pins_notify_mask(d->inputs, d->num_inputs,
+ ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs,
phase_offset_ntf);
resched:
--
2.52.0