Thread (8 messages) flat view 8 messages, 3 authors, 4d ago

Re: [PATCH net-next 3/3] ice: use per-interface clock_id for E825 generic DPLLs

From: netdev-bot+sashiko@kernel.org
Date: 2026-09-11 10:27:13

Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 3 · Low: 0

- [Medium] In ice_dpll_init_txclk_pins()
  (drivers/net/ethernet/intel/ice/ice_dpll.c:4279-4282) the board-level…
- [Medium] ice_dpll_pin_notify()
  (drivers/net/ethernet/intel/ice/ice_dpll.c:3928) replaces the board-…
- [Medium] ice_generate_dpll_clock_id()
  (drivers/net/ethernet/intel/ice/ice_dpll.c:3086-3092) feeds…

--

ice: use per-interface clock_id for E825 generic DPLLs

On E825 the TX-CLK and TSPLL generic DPLL devices no longer take their
clock_id from the board-level PCIe DSN, but from the permanent port MAC
(TSPLL adds BIT_ULL(63) as a tag).  The notifier self-suppression check in
ice_dpll_pin_notify() is extended with a new helper that compares the
incoming src_clock_id against this PF's board, TXC and TSPLL clock_ids.
quoted hunk ↗ jump to hunk
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
@@ -3059,6 +3059,68 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
 	return pci_get_dsn(pf->pdev);
 }
 
+/**
+ * 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;
+}
[Severity: Medium]
Are these two values still valid clock identifiers as far as the dpll uAPI
is concerned?  Documentation/driver-api/dpll.rst describes the field as:

  ``DPLL_A_CLOCK_ID``                attr Unique Clock Identifier
                                         (EUI-64), as defined by the
                                         IEEE 1588 standard

and dpll_msg_add_dev_handle() exports the driver value verbatim with
nla_put_64bit(msg, DPLL_A_CLOCK_ID, ...), so whatever is stored here
becomes uAPI.

ether_addr_to_u64() packs the six MAC bytes into the low 48 bits and leaves
bits 48-63 zero, which is not the MAC-48 to EUI-64 mapping IEEE 1588 asks
for (OUI[0..2] || FF FE || NIC[3..5]).  The same driver keeps feeding the
same attribute a genuine EUI-64 for the EEC/PPS and non-E825 objects:

	static u64 ice_generate_clock_id(struct ice_pf *pf)
	{
		return pci_get_dsn(pf->pdev);
	}

Should the MAC be expanded into a proper EUI-64 so both producers in this
driver use one format?

For the TSPLL variant, mac_clock_id | BIT_ULL(63) sets a bit inside what
would be the first octet of the OUI, so it can collide with a real clock
identifier starting 80:00, and the exported value no longer visibly matches
the interface MAC that the commit message wants userspace to key on.

Is the tag bit needed at all?  dpll_device_get() matches on (clock_id,
device_idx, module):

	if (dpll->clock_id == clock_id &&
	    dpll->device_idx == device_idx &&
	    dpll->module == module) {

and TSPLL uses E825_DPLL_TSPLL_BASE_IDX while TX-CLK uses
E825_DPLL_TXCLK_BASE_IDX and above, so the device_idx already separates the
two objects.
+
+/**
+ * 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);
+}
[Severity: Medium]
Does this helper still cover notifications generated by a sibling PF of the
same NAC?

The old test compared src_clock_id against pf->dplls.clock_id, which is
pci_get_dsn() and, as the commit message says, "identical for all interfaces
sharing the same NAC/quad".  It therefore matched register/unregister events
raised by any PF on the board.  The new helper only matches this PF's three
values: board DSN, MAC(self) and MAC(self) | BIT(63).

The notification carries the target DPLL device's clock_id.  In
__dpll_pin_unregister():

	dpll_pin_delete_ntf(pin, dpll->clock_id);

so for the shared fwnode SYNCE pin the value is now MAC(sibling PF), which
ice_dpll_is_own_dpll_clock_id() rejects.

If PF-A is unbound:

  ice_dpll_deinit() -> ice_dpll_deinit_txclk_pins() ->
  ice_dpll_unregister_pins() -> dpll_pin_unregister(PF-A txc dpll, synce pin)
  -> __dpll_pin_unregister() -> dpll_pin_delete_ntf(pin, MAC(PF-A))

PF-B's ice_dpll_pin_notify() passes the fwnode test (it is the same shared
pin), the new clock_id test returns false, work gets queued, and
ice_dpll_pin_notify_work() takes the DPLL_PIN_DELETED branch:

	} else if (is_tx_synce_parent) {
		/* Unregister TX-CLK SYNCE pin from TXC DPLL */
		pin = &pf->dplls.txclks[E825_EXT_SYNCE_PIN_IDX];
		dpll_pin_unregister(pf->dplls.txc.dpll, pin->pin,
				    &ice_dpll_txclk_ops, pin);

Can this tear down PF-B's own still-valid SYNCE registration, so that after
unbinding one PF the surviving ports of the same NAC can no longer select
SyncE as TX reference?

This depends on both PFs' clk_ref_synce reference resolving to the same
fwnode object, which is what ice_dpll_pin_node_get() looks up and what
ice_txclk_enable_peer() suggests when it notes that SyncE must be enabled on
both PHY complexes.  If that is how the platform description is expected to
look, should the helper also accept clock_ids belonging to other PFs of the
same board, or should the suppression be keyed on something other than the
clock_id?
quoted hunk ↗ jump to hunk
@@ -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,
[Severity: Medium]
Does this change how many pin objects the single physical EXT_EREF0
connector produces?

dpll_pin_get() keys pin identity on (clock_id, pin_idx, module):

	if (pos->clock_id == clock_id &&
	    pos->pin_idx == pin_idx &&
	    pos->module == module) {

Every PF reaches here with the same start_idx, so with the board DSN all
PFs of a NAC obtained the same dpll_pin object for EREF0 and each registered
it on its own TX-CLK DPLL device, i.e. one pin with several parent DPLLs.
With the MAC-derived clock_id the lookup can no longer match a sibling PF's
pin, so each PF allocates a private pin object.

EREF0 is described as a board-level signal in
ice_dpll_init_info_txclk_pins_e825c():

	tx_pin->prop.board_label = ice_dpll_ext_eref_pin;
	tx_pin->tx_ref_src = ICE_REF_CLK_EREF0;

Does userspace then see N pins all labelled "EXT_EREF0" with no indication
that they are the same input?  The sibling input of the same TX-CLK DPLL
(EXT_SYNCE, fwnode-backed) stays a single shared pin with several parent
DPLLs, so the two external TX reference inputs of one DPLL device end up
modelled differently.

The commit message only talks about DPLL devices:

  "Since these DPLLs are per-interface, use the permanent port MAC as
   the clock_id basis for E825 generic DPLLs"

Could it also mention that DPLL_A_PIN_CLOCK_ID and the number of exported
EREF0 pin objects change, since that is userspace-visible as well?

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260908222428.872254-1-anthony.l.nguyen%40intel.com
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help