summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Nitka <grzegorz.nitka@intel.com>2026-08-03 13:35:07 +0200
committerTony Nguyen <anthony.l.nguyen@intel.com>2026-09-08 09:41:53 -0700
commit97bd063c08a27d0cc5c9367cca5590725c970fa6 (patch)
tree3fd3bf1ee8c237acd7d75e2599b95462839dbfcb
parent41dfc378867f012b3c6c9feb72da0a15a675685d (diff)
downloadlinux-next-97bd063c08a27d0cc5c9367cca5590725c970fa6.tar.gz
linux-next-97bd063c08a27d0cc5c9367cca5590725c970fa6.zip
ice: use per-interface clock_id for E825 generic DPLLs
On E825, the TX-CLK and TSPLL DPLL devices are registered as DPLL_TYPE_GENERIC. Their clock_id was derived from the board-level PCIe DSN, which is identical for all interfaces sharing the same NAC/quad. As a result, userspace (e.g. 'dpll device show') reports several DPLL devices with the same clock_id and no board or signal label, making it impossible to unambiguously map a DPLL device to the interface it belongs to. Since these DPLLs are per-interface, use the permanent port MAC as the clock_id basis for E825 generic DPLLs: * TX-CLK uses the plain MAC-derived value. * TSPLL on the source-timer owner PF uses the same MAC-derived value with a dedicated tag bit, so it stays distinct from TX-CLK while remaining stable per interface. Other DPLL objects (EEC/PPS and non-E825 paths) keep the board DSN-derived clock_id. When the permanent MAC is not yet valid, fall back to the existing board-level clock_id to preserve init behavior. Reviewed-by: Przemyslaw Korba <przemyslaw.korba@intel.com> Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com> Tested-by: Alexander Nowlin <alexander.nowlin@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.c80
1 files changed, 75 insertions, 5 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 00e3f7de7810..0109fc34307c 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -3060,6 +3060,68 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
}
/**
+ * ice_generate_dpll_clock_id - generate clock_id for a specific dpll device
+ * @pf: board private structure
+ * @d: dpll device context
+ * @type: dpll type being registered
+ *
+ * For E825 generic DPLLs, use per-interface permanent MAC as the clock_id
+ * basis so userspace can unambiguously map DPLL devices to interfaces.
+ * TX-CLK keeps plain MAC-derived ID, while TSPLL uses the same basis with
+ * a dedicated tag bit to remain distinct on source-timer owner PFs.
+ * Other DPLL objects keep board-level DSN-derived clock_id.
+ *
+ * Return: generated clock id for a dpll device
+ */
+static u64 ice_generate_dpll_clock_id(struct ice_pf *pf, struct ice_dpll *d,
+ enum dpll_type type)
+{
+ struct ice_hw *hw = &pf->hw;
+ u64 mac_clock_id;
+
+ if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 &&
+ type == DPLL_TYPE_GENERIC &&
+ hw->port_info &&
+ is_valid_ether_addr(hw->port_info->mac.perm_addr)) {
+ mac_clock_id = ether_addr_to_u64(hw->port_info->mac.perm_addr);
+
+ if (d->dpll_idx >= E825_DPLL_TXCLK_BASE_IDX)
+ return mac_clock_id;
+
+ if (d->dpll_idx == E825_DPLL_TSPLL_BASE_IDX)
+ return mac_clock_id | BIT_ULL(63);
+ }
+
+ return pf->dplls.clock_id;
+}
+
+/**
+ * ice_dpll_is_own_dpll_clock_id - check if clock_id belongs to this pf's DPLLs
+ * @pf: board private structure
+ * @clock_id: clock_id from a DPLL notification
+ *
+ * Match info->src_clock_id from a DPLL pin notification against any DPLL
+ * device this PF has registered. Used to suppress self-notifications
+ * generated as a side effect of our own dpll_pin_register() and
+ * dpll_pin_unregister() calls on the fwnode-backed SYNCE and TIME_REF pins,
+ * whose DPLLs (TXC and TSPLL) use MAC-derived clock_ids on E825.
+ *
+ * Return: true if clock_id matches one of this PF's registered DPLL devices.
+ */
+static bool ice_dpll_is_own_dpll_clock_id(struct ice_pf *pf, u64 clock_id)
+{
+ if (clock_id == pf->dplls.clock_id)
+ return true;
+ if (pf->hw.mac_type != ICE_MAC_GENERIC_3K_E825)
+ return false;
+ if (clock_id == ice_generate_dpll_clock_id(pf, &pf->dplls.txc,
+ DPLL_TYPE_GENERIC))
+ return true;
+ return clock_id == ice_generate_dpll_clock_id(pf, &pf->dplls.tspll,
+ DPLL_TYPE_GENERIC);
+}
+
+/**
* ice_dpll_pin_ntf - notify pin change including any SW pin wrappers
* @dplls: pointer to dplls struct
* @pin: the dpll_pin that changed
@@ -3858,10 +3920,12 @@ static int ice_dpll_pin_notify(struct notifier_block *nb, unsigned long action,
if (pin->fwnode != info->fwnode)
return NOTIFY_DONE; /* Not this pin */
- /* Ignore notification which are the outcome of internal pin
- * registration/unregistration calls - synce pin case.
+ /* Ignore notifications that are a side effect of internal pin
+ * registration/unregistration calls. E825 uses per-device
+ * MAC-derived clock_ids for the TXC and TSPLL generic DPLLs, so
+ * info->src_clock_id may not equal pf->dplls.clock_id.
*/
- if (info->src_clock_id == pin->pf->dplls.clock_id)
+ if (ice_dpll_is_own_dpll_clock_id(pin->pf, info->src_clock_id))
return NOTIFY_DONE;
work = kzalloc_obj(*work);
@@ -4206,10 +4270,16 @@ static int ice_dpll_init_txclk_pins(struct ice_pf *pf, int start_idx)
{
struct ice_dpll_pin *ref_pin = pf->dplls.txclks;
struct ice_dpll *txc = &pf->dplls.txc;
+ u64 clock_id;
int ret;
+ /* EXT_EREF0 is a non-fwnode pin; its clock_id must match the TX-CLK
+ * DPLL device clock_id (see dpll_pin_register()).
+ */
+ clock_id = ice_generate_dpll_clock_id(pf, txc, DPLL_TYPE_GENERIC);
+
/* Configure EXT_EREF0 pin */
- ret = ice_dpll_get_pins(pf, ref_pin, start_idx, 1, pf->dplls.clock_id);
+ ret = ice_dpll_get_pins(pf, ref_pin, start_idx, 1, clock_id);
if (ret)
return ret;
ret = dpll_pin_register(txc->dpll, ref_pin->pin, &ice_dpll_txclk_ops,
@@ -4487,7 +4557,7 @@ static int
ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
enum dpll_type type)
{
- u64 clock_id = pf->dplls.clock_id;
+ u64 clock_id = ice_generate_dpll_clock_id(pf, d, type);
int ret;
d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE,