* [RFC PATCH v2] net: add net-device TX clock source selection framework
@ 2025-08-28 16:43 Arkadiusz Kubalewski
2025-08-28 16:57 ` Mina Almasry
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Arkadiusz Kubalewski @ 2025-08-28 16:43 UTC (permalink / raw)
To: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
edumazet, kuba, pabeni, horms, sdf, almasrymina, asml.silence,
leitao, kuniyu, jiri, aleksandr.loktionov, ivecera
Cc: linux-kernel, intel-wired-lan, netdev, Arkadiusz Kubalewski
Add support for user-space control over network device transmit clock
sources through a new extended netdevice netlink interface.
A network device may support multiple TX clock sources (OCXO, SyncE
reference, external reference clocks) which are critical for
time-sensitive networking applications and synchronization protocols.
Key features:
- per-netdev TX clock source selection via netlink commands
- clock sharing between PFs on same PCI device with independent state,
sharing detection using PCI Device Serial Numbers (DSN)
- defined clock types enums
- Notification system for clock state changes
Netlink interface
- tx-clk-get: Query available clock sources and current state
- tx-clk-set: Switch to specified clock source
- tx-clk-change-ntf: Notifications for clock state changes
Kconfig option NET_TX_CLK:
- optional feature + user documentation
Intel's ice driver integration:
- support for OCXO, EXT_REF, and SYNCE clock types
- initialization and cleanup with individual unregistration
- per-PF clock state management
Check the state:
$ <ynl> --spec Documentation/netlink/specs/netdev.yaml \
--do tx-clk-get --json '{"ifindex":8}'
[{'active': True, 'ifindex': 8, 'type': 'ocxo'},
{'ifindex': 8, 'type': 'ext-ref'},
{'ifindex': 8, 'type': 'synce'}]
-> Currently using OCXO (shows `'active': True`)
Switch to External Reference:
$ <ynl> --spec Documentation/netlink/specs/netdev.yaml \
--do tx-clk-set --json '{"ifindex":8, "type":"ext-ref"}'
Verify the change:
$ <ynl> --spec Documentation/netlink/specs/netdev.yaml \
--do tx-clk-get --json '{"ifindex":8}'
[{'ifindex': 8, 'type': 'ocxo'},
{'active': True, 'ifindex': 8, 'type': 'ext-ref'},
{'ifindex': 8, 'type': 'synce'}]
Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
---
v2:
- use netlink instead of sysfs
- defined clok type enums
---
Documentation/netlink/specs/netdev.yaml | 61 +++++
drivers/net/ethernet/intel/ice/Makefile | 1 +
drivers/net/ethernet/intel/ice/ice.h | 5 +
drivers/net/ethernet/intel/ice/ice_lib.c | 6 +
drivers/net/ethernet/intel/ice/ice_main.c | 6 +
drivers/net/ethernet/intel/ice/ice_tx_clk.c | 100 +++++++
drivers/net/ethernet/intel/ice/ice_tx_clk.h | 17 ++
include/linux/netdev_tx_clk.h | 92 +++++++
include/linux/netdevice.h | 4 +
include/uapi/linux/netdev.h | 18 ++
net/Kconfig | 21 ++
net/core/Makefile | 1 +
net/core/netdev-genl-gen.c | 37 +++
net/core/netdev-genl-gen.h | 4 +
net/core/netdev-genl.c | 287 ++++++++++++++++++++
net/core/tx_clk.c | 218 +++++++++++++++
net/core/tx_clk.h | 36 +++
tools/include/uapi/linux/netdev.h | 18 ++
18 files changed, 932 insertions(+)
create mode 100644 drivers/net/ethernet/intel/ice/ice_tx_clk.c
create mode 100644 drivers/net/ethernet/intel/ice/ice_tx_clk.h
create mode 100644 include/linux/netdev_tx_clk.h
create mode 100644 net/core/tx_clk.c
create mode 100644 net/core/tx_clk.h
diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index c035dc0f64fd..450ce39a4527 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -89,6 +89,10 @@ definitions:
name: napi-threaded
type: enum
entries: [disabled, enabled]
+ -
+ name: tx-clk-type
+ type: enum
+ entries: [ocxo, ext-ref, synce]
attribute-sets:
-
@@ -561,6 +565,25 @@ attribute-sets:
type: u32
checks:
min: 1
+ -
+ name: tx-clk
+ doc: netdev TX clock source configuration and status
+ attributes:
+ -
+ name: ifindex
+ doc: ifindex of the netdevice
+ type: u32
+ checks:
+ min: 1
+ -
+ name: type
+ doc: type of the TX clock source
+ type: u32
+ enum: tx-clk-type
+ -
+ name: active
+ doc: present only when this clock source is currently active
+ type: flag
operations:
list:
@@ -771,6 +794,44 @@ operations:
reply:
attributes:
- id
+ -
+ name: tx-clk-get
+ doc: get information about TX clock sources for a device.
+ attribute-set: tx-clk
+ do:
+ request:
+ attributes:
+ - ifindex
+ reply: &tx-clk-get-reply
+ attributes:
+ - ifindex
+ - type
+ - active
+ dump:
+ request:
+ attributes:
+ - ifindex
+ reply: *tx-clk-get-reply
+ -
+ name: tx-clk-set
+ doc: set the active TX clock source for a device.
+ attribute-set: tx-clk
+ flags: [admin-perm]
+ do:
+ request:
+ attributes:
+ - ifindex
+ - type
+ reply:
+ attributes:
+ - ifindex
+ - type
+ - active
+ -
+ name: tx-clk-change-ntf
+ doc: notification about TX clock source being changed.
+ notify: tx-clk-get
+ mcgrp: mgmt
kernel-family:
headers: ["net/netdev_netlink.h"]
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 5d5e89c5ccfa..d1997b370ae1 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -61,3 +61,4 @@ ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
ice-$(CONFIG_ICE_SWITCHDEV) += ice_eswitch.o ice_eswitch_br.o
ice-$(CONFIG_GNSS) += ice_gnss.o
ice-$(CONFIG_ICE_HWMON) += ice_hwmon.o
+ice-$(CONFIG_NET_TX_CLK) += ice_tx_clk.o
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index b413bd066fab..e8ec0528d73b 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -205,6 +205,7 @@ enum ice_feature {
ICE_F_SRIOV_LAG,
ICE_F_SRIOV_AA_LAG,
ICE_F_MBX_LIMIT,
+ ICE_F_TX_CLK,
ICE_F_MAX
};
@@ -661,6 +662,10 @@ struct ice_pf {
struct device *hwmon_dev;
struct ice_health health_reporters;
struct iidc_rdma_core_dev_info *cdev_info;
+#ifdef CONFIG_NET_TX_CLK
+ void *tx_clk_data;
+ enum netdev_tx_clk_type tx_clk_active;
+#endif
u8 num_quanta_prof_used;
};
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 8fff6c87fb61..0202e7cbe87c 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -3942,6 +3942,12 @@ void ice_init_feature_support(struct ice_pf *pf)
if (ice_gnss_is_module_present(&pf->hw))
ice_set_feature_support(pf, ICE_F_GNSS);
break;
+ case ICE_DEV_ID_E825C_BACKPLANE:
+ case ICE_DEV_ID_E825C_QSFP:
+ case ICE_DEV_ID_E825C_SFP:
+ case ICE_DEV_ID_E825C_SGMII:
+ ice_set_feature_support(pf, ICE_F_TX_CLK);
+ break;
default:
break;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 848d5b512319..44eb58618e05 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -27,6 +27,7 @@
#include "ice_tc_lib.h"
#include "ice_vsi_vlan_ops.h"
#include <net/xdp_sock_drv.h>
+#include "ice_tx_clk.h"
#define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver"
static const char ice_driver_string[] = DRV_SUMMARY;
@@ -4824,6 +4825,9 @@ static void ice_init_features(struct ice_pf *pf)
if (ice_init_lag(pf))
dev_warn(dev, "Failed to init link aggregation support\n");
+ if (ice_is_feature_supported(pf, ICE_F_TX_CLK))
+ ice_tx_clk_init(pf);
+
ice_hwmon_init(pf);
}
@@ -4844,6 +4848,8 @@ static void ice_deinit_features(struct ice_pf *pf)
ice_dpll_deinit(pf);
if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
xa_destroy(&pf->eswitch.reprs);
+ if (ice_is_feature_supported(pf, ICE_F_TX_CLK))
+ ice_tx_clk_deinit(pf);
}
static void ice_init_wakeup(struct ice_pf *pf)
diff --git a/drivers/net/ethernet/intel/ice/ice_tx_clk.c b/drivers/net/ethernet/intel/ice/ice_tx_clk.c
new file mode 100644
index 000000000000..006310eefb8b
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_tx_clk.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2025, Intel Corporation. */
+
+#include <linux/netdev_tx_clk.h>
+#include "ice_tx_clk.h"
+
+struct ice_tx_clk_data {
+ struct ice_pf *pf;
+ enum netdev_tx_clk_type type;
+};
+
+static const struct netdev_tx_clk_ops ice_tx_clk_ops;
+
+static int ice_tx_clk_enable(void *priv_data)
+{
+ struct ice_tx_clk_data *clk_data = priv_data;
+ struct ice_pf *pf = clk_data->pf;
+ enum netdev_tx_clk_type type;
+
+ type = clk_data->type;
+ if (type < NETDEV_TX_CLK_TYPE_OCXO || type > NETDEV_TX_CLK_TYPE_SYNCE) {
+ dev_err(ice_pf_to_dev(pf), "Invalid clock type: %d\n", type);
+ return -EINVAL;
+ }
+ if (pf->tx_clk_active != type) {
+ dev_dbg(ice_pf_to_dev(pf), "PF%d switching from clock %d to clock %d\n",
+ pf->hw.pf_id, pf->tx_clk_active, type);
+ pf->tx_clk_active = type;
+ /* TODO: add TX clock switching logic */
+ }
+
+ return 0;
+}
+
+static int ice_tx_clk_is_enabled(void *priv_data)
+{
+ struct ice_tx_clk_data *clk_data = priv_data;
+ struct ice_pf *pf = clk_data->pf;
+ enum netdev_tx_clk_type type =
+ clk_data->type;
+
+ return (pf->tx_clk_active == type) ? 1 : 0;
+}
+
+static const struct netdev_tx_clk_ops ice_tx_clk_ops = {
+ .enable = ice_tx_clk_enable,
+ .is_enabled = ice_tx_clk_is_enabled,
+};
+
+void ice_tx_clk_init(struct ice_pf *pf)
+{
+ struct ice_tx_clk_data *clk_data[NETDEV_TX_CLK_TYPE_SYNCE + 1];
+ struct ice_vsi *vsi = ice_get_main_vsi(pf);
+ int i, ret;
+
+ if (!vsi || !vsi->netdev)
+ return;
+
+ for (i = NETDEV_TX_CLK_TYPE_OCXO; i <= NETDEV_TX_CLK_TYPE_SYNCE; i++) {
+ clk_data[i] = kzalloc(sizeof(*clk_data[i]), GFP_KERNEL);
+ if (!clk_data[i]) {
+ while (--i >= 0)
+ kfree(clk_data[i]);
+ return;
+ }
+
+ clk_data[i]->pf = pf;
+ clk_data[i]->type = i;
+ }
+
+ pf->tx_clk_active = NETDEV_TX_CLK_TYPE_OCXO;
+
+ for (i = NETDEV_TX_CLK_TYPE_OCXO; i <= NETDEV_TX_CLK_TYPE_SYNCE; i++) {
+ ret = netdev_tx_clk_register(vsi->netdev, i,
+ &ice_tx_clk_ops, clk_data[i]);
+ if (ret) {
+ dev_err(ice_pf_to_dev(pf),
+ "Failed to register clock type %d: %d\n",
+ i, ret);
+ }
+ }
+
+ dev_dbg(ice_pf_to_dev(pf), "ICE TX clocks initialized for PF%d (default: OCXO)\n",
+ pf->hw.pf_id);
+}
+
+void ice_tx_clk_deinit(struct ice_pf *pf)
+{
+ struct ice_vsi *vsi = ice_get_main_vsi(pf);
+ int i;
+
+ if (!vsi || !vsi->netdev)
+ return;
+
+ for (i = NETDEV_TX_CLK_TYPE_OCXO; i <= NETDEV_TX_CLK_TYPE_SYNCE; i++)
+ netdev_tx_clk_unregister(vsi->netdev, i);
+
+ dev_dbg(ice_pf_to_dev(pf), "ICE TX clocks deinitialized for PF%d\n",
+ pf->hw.pf_id);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_tx_clk.h b/drivers/net/ethernet/intel/ice/ice_tx_clk.h
new file mode 100644
index 000000000000..02ede41dfefa
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_tx_clk.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2025, Intel Corporation. */
+
+#ifndef _ICE_TX_CLK_H_
+#define _ICE_TX_CLK_H_
+
+#include "ice.h"
+
+#if IS_ENABLED(CONFIG_NET_TX_CLK)
+void ice_tx_clk_init(struct ice_pf *pf);
+void ice_tx_clk_deinit(struct ice_pf *pf);
+#else
+static inline void ice_tx_clk_init(struct ice_pf *pf) { }
+static inline void ice_tx_clk_deinit(struct ice_pf *pf) { }
+#endif
+
+#endif /* _ICE_TX_CLK_H_ */
diff --git a/include/linux/netdev_tx_clk.h b/include/linux/netdev_tx_clk.h
new file mode 100644
index 000000000000..7a8ed832d052
--- /dev/null
+++ b/include/linux/netdev_tx_clk.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * netdev_tx_clk.h - allow net_device TX clock control
+ * Author: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
+ */
+
+#ifndef __NETDEV_TX_CLK_H
+#define __NETDEV_TX_CLK_H
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/kref.h>
+#include <uapi/linux/netdev.h>
+
+/**
+ * struct netdev_tx_clk_ops - TX clock operations
+ * @enable: switch to this clock
+ * @is_enabled: check if this clock is currently active for this netdev
+ *
+ * Note: Multiple netdevs can share the same physical clock but control
+ * it independently. The same clock may be active for some netdevs and
+ * inactive for others.
+ */
+struct netdev_tx_clk_ops {
+ int (*enable)(void *priv_data);
+ int (*is_enabled)(void *priv_data);
+};
+
+#if IS_ENABLED(CONFIG_NET_TX_CLK)
+/**
+ * netdev_tx_clk_register - Register a TX clock for a network device
+ * @ndev: Network device
+ * @clk_type: Type of clock (OCXO, SYNCE, EXT_REF)
+ * @ops: Clock operations
+ * @priv_data: Private data passed to operations
+ *
+ * This function registers a TX clock that can be shared across multiple
+ * network functions on the same PCI device. The system generates a unique
+ * clock ID based on PCI Device Serial Number and clock type.
+ *
+ * Clock sharing behavior:
+ * - Physical clock resources are shared between PFs on the same PCI device
+ * - Each PF maintains independent logical state (enabled/disabled)
+ * - The @priv_data allows per-PF state tracking while sharing hardware
+ *
+ * Returns: 0 on success, negative error code on failure
+ */
+int netdev_tx_clk_register(struct net_device *ndev,
+ enum netdev_tx_clk_type clk_type,
+ const struct netdev_tx_clk_ops *ops,
+ void *priv_data);
+
+void netdev_tx_clk_unregister(struct net_device *ndev,
+ enum netdev_tx_clk_type clk_type);
+
+/* Helper functions for netdev-genl.c */
+struct netdev_tx_clk_data *netdev_get_tx_clk_data(struct net_device *ndev);
+struct netdev_tx_clk_ref *
+netdev_find_tx_clk_ref(struct netdev_tx_clk_data *data,
+ enum netdev_tx_clk_type clk_type);
+
+#else
+static inline int netdev_tx_clk_register(struct net_device *ndev,
+ enum netdev_tx_clk_type clk_type,
+ const struct netdev_tx_clk_ops *ops,
+ void *priv_data)
+{
+ return 0;
+}
+
+static inline void netdev_tx_clk_unregister(struct net_device *ndev,
+ enum netdev_tx_clk_type clk_type)
+{ }
+
+static inline struct netdev_tx_clk_data *
+netdev_get_tx_clk_data(struct net_device *ndev)
+{
+ return NULL;
+}
+
+static inline struct netdev_tx_clk_ref *
+netdev_find_tx_clk_ref(struct netdev_tx_clk_data *data,
+ enum netdev_tx_clk_type clk_type,
+ u32 user_clk_id)
+{
+ return NULL;
+}
+
+#endif
+#endif /* __NETDEV_TX_CLK_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f3a3b761abfb..0971adfd58b5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -84,6 +84,7 @@ struct xdp_md;
struct ethtool_netdev_state;
struct phy_link_topology;
struct hwtstamp_provider;
+struct netdev_tx_clk_data;
typedef u32 xdp_features_t;
@@ -2555,6 +2556,9 @@ struct net_device {
struct hwtstamp_provider __rcu *hwprov;
+#if IS_ENABLED(CONFIG_NET_TX_CLK)
+ struct netdev_tx_clk_data *tx_clk_data;
+#endif
u8 priv[] ____cacheline_aligned
__counted_by(priv_len);
} ____cacheline_aligned;
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index 48eb49aa03d4..e7ff67474246 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -82,6 +82,12 @@ enum netdev_napi_threaded {
NETDEV_NAPI_THREADED_ENABLED,
};
+enum netdev_tx_clk_type {
+ NETDEV_TX_CLK_TYPE_OCXO,
+ NETDEV_TX_CLK_TYPE_EXT_REF,
+ NETDEV_TX_CLK_TYPE_SYNCE,
+};
+
enum {
NETDEV_A_DEV_IFINDEX = 1,
NETDEV_A_DEV_PAD,
@@ -210,6 +216,15 @@ enum {
NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1)
};
+enum {
+ NETDEV_A_TX_CLK_IFINDEX = 1,
+ NETDEV_A_TX_CLK_TYPE,
+ NETDEV_A_TX_CLK_ACTIVE,
+
+ __NETDEV_A_TX_CLK_MAX,
+ NETDEV_A_TX_CLK_MAX = (__NETDEV_A_TX_CLK_MAX - 1)
+};
+
enum {
NETDEV_CMD_DEV_GET = 1,
NETDEV_CMD_DEV_ADD_NTF,
@@ -226,6 +241,9 @@ enum {
NETDEV_CMD_BIND_RX,
NETDEV_CMD_NAPI_SET,
NETDEV_CMD_BIND_TX,
+ NETDEV_CMD_TX_CLK_GET,
+ NETDEV_CMD_TX_CLK_SET,
+ NETDEV_CMD_TX_CLK_CHANGE_NTF,
__NETDEV_CMD_MAX,
NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
diff --git a/net/Kconfig b/net/Kconfig
index d5865cf19799..9657bc2fb7a2 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -541,4 +541,25 @@ config NET_TEST
If unsure, say N.
+config NET_TX_CLK
+ bool "Control over source of TX clock per network device"
+ depends on NET
+ default n
+ help
+ This feature enables per-network-port control over TX clock sources
+ in networking hardware through a netlink interface. Network devices
+ may support multiple TX clock sources such as OCXOs (Oven
+ Controlled Crystal Oscillators), external reference signals, or
+ SyncE (Synchronous Ethernet) recovered clocks.
+
+ When enabled, supported network devices can be controlled via the
+ netdev netlink family using tx-clk-get, tx-clk-set, and tx-clk-dump
+ commands.
+
+ This could be useful for applications requiring precise timing
+ control, such as time-sensitive networking (TSN), synchronization
+ protocols, and PTP (Precision Time Protocol) implementations.
+
+ If unsure, say N.
+
endif # if NET
diff --git a/net/core/Makefile b/net/core/Makefile
index b2a76ce33932..7e4031813b18 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -47,3 +47,4 @@ obj-$(CONFIG_NET_TEST) += net_test.o
obj-$(CONFIG_NET_DEVMEM) += devmem.o
obj-$(CONFIG_DEBUG_NET) += lock_debug.o
obj-$(CONFIG_FAIL_SKB_REALLOC) += skb_fault_injection.o
+obj-$(CONFIG_NET_TX_CLK) += tx_clk.o
diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c
index e9a2a6f26cb7..72e822b9b005 100644
--- a/net/core/netdev-genl-gen.c
+++ b/net/core/netdev-genl-gen.c
@@ -106,6 +106,22 @@ static const struct nla_policy netdev_bind_tx_nl_policy[NETDEV_A_DMABUF_FD + 1]
[NETDEV_A_DMABUF_FD] = { .type = NLA_U32, },
};
+/* NETDEV_CMD_TX_CLK_GET - do */
+static const struct nla_policy netdev_tx_clk_get_do_nl_policy[NETDEV_A_TX_CLK_IFINDEX + 1] = {
+ [NETDEV_A_TX_CLK_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1),
+};
+
+/* NETDEV_CMD_TX_CLK_GET - dump */
+static const struct nla_policy netdev_tx_clk_get_dump_nl_policy[NETDEV_A_TX_CLK_IFINDEX + 1] = {
+ [NETDEV_A_TX_CLK_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1),
+};
+
+/* NETDEV_CMD_TX_CLK_SET - do */
+static const struct nla_policy netdev_tx_clk_set_nl_policy[NETDEV_A_TX_CLK_TYPE + 1] = {
+ [NETDEV_A_TX_CLK_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1),
+ [NETDEV_A_TX_CLK_TYPE] = NLA_POLICY_MAX(NLA_U32, 2),
+};
+
/* Ops table for netdev */
static const struct genl_split_ops netdev_nl_ops[] = {
{
@@ -204,6 +220,27 @@ static const struct genl_split_ops netdev_nl_ops[] = {
.maxattr = NETDEV_A_DMABUF_FD,
.flags = GENL_CMD_CAP_DO,
},
+ {
+ .cmd = NETDEV_CMD_TX_CLK_GET,
+ .doit = netdev_nl_tx_clk_get_doit,
+ .policy = netdev_tx_clk_get_do_nl_policy,
+ .maxattr = NETDEV_A_TX_CLK_IFINDEX,
+ .flags = GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = NETDEV_CMD_TX_CLK_GET,
+ .dumpit = netdev_nl_tx_clk_get_dumpit,
+ .policy = netdev_tx_clk_get_dump_nl_policy,
+ .maxattr = NETDEV_A_TX_CLK_IFINDEX,
+ .flags = GENL_CMD_CAP_DUMP,
+ },
+ {
+ .cmd = NETDEV_CMD_TX_CLK_SET,
+ .doit = netdev_nl_tx_clk_set_doit,
+ .policy = netdev_tx_clk_set_nl_policy,
+ .maxattr = NETDEV_A_TX_CLK_TYPE,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
};
static const struct genl_multicast_group netdev_nl_mcgrps[] = {
diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h
index cf3fad74511f..db524e7b82d7 100644
--- a/net/core/netdev-genl-gen.h
+++ b/net/core/netdev-genl-gen.h
@@ -35,6 +35,10 @@ int netdev_nl_qstats_get_dumpit(struct sk_buff *skb,
int netdev_nl_bind_rx_doit(struct sk_buff *skb, struct genl_info *info);
int netdev_nl_napi_set_doit(struct sk_buff *skb, struct genl_info *info);
int netdev_nl_bind_tx_doit(struct sk_buff *skb, struct genl_info *info);
+int netdev_nl_tx_clk_get_doit(struct sk_buff *skb, struct genl_info *info);
+int netdev_nl_tx_clk_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb);
+int netdev_nl_tx_clk_set_doit(struct sk_buff *skb, struct genl_info *info);
enum {
NETDEV_NLGRP_MGMT,
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index 6314eb7bdf69..d470003dd7e5 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/netdevice.h>
+#include <linux/netdev_tx_clk.h>
#include <linux/notifier.h>
#include <linux/rtnetlink.h>
#include <net/busy_poll.h>
@@ -15,6 +16,7 @@
#include "dev.h"
#include "devmem.h"
#include "netdev-genl-gen.h"
+#include "tx_clk.h"
struct netdev_nl_dump_ctx {
unsigned long ifindex;
@@ -1136,4 +1138,289 @@ static int __init netdev_genl_init(void)
return err;
}
+#ifdef CONFIG_NET_TX_CLK
+static void netdev_tx_clk_notify_change(struct net_device *ndev,
+ enum netdev_tx_clk_type clk_type,
+ bool active)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = genlmsg_put(msg, 0, 0, &netdev_nl_family, 0,
+ NETDEV_CMD_TX_CLK_CHANGE_NTF);
+ if (!hdr)
+ goto err_free_msg;
+
+ if (nla_put_u32(msg, NETDEV_A_TX_CLK_IFINDEX, ndev->ifindex) ||
+ nla_put_u32(msg, NETDEV_A_TX_CLK_TYPE, clk_type))
+ goto err_cancel_msg;
+
+ if (active) {
+ if (nla_put_flag(msg, NETDEV_A_TX_CLK_ACTIVE))
+ goto err_cancel_msg;
+ }
+
+ genlmsg_end(msg, hdr);
+ genlmsg_multicast(&netdev_nl_family, msg, 0, NETDEV_NLGRP_MGMT,
+ GFP_KERNEL);
+ return;
+
+err_cancel_msg:
+ genlmsg_cancel(msg, hdr);
+err_free_msg:
+ nlmsg_free(msg);
+}
+
+static int netdev_nl_tx_clk_dump_one(struct sk_buff *rsp,
+ struct net_device *netdev,
+ struct netdev_tx_clk_ref *ref,
+ const struct genl_info *info)
+{
+ struct netdev_tx_clk_global_entry *entry = ref->global_entry;
+ void *hdr;
+
+ hdr = genlmsg_iput(rsp, info);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (nla_put_u32(rsp, NETDEV_A_TX_CLK_IFINDEX, netdev->ifindex) ||
+ nla_put_u32(rsp, NETDEV_A_TX_CLK_TYPE, entry->key.clk_type)) {
+ genlmsg_cancel(rsp, hdr);
+ return -EMSGSIZE;
+ }
+
+ if (entry->ops && entry->ops->is_enabled) {
+ int enabled = entry->ops->is_enabled(ref->priv_data);
+
+ if (enabled > 0) {
+ if (nla_put_flag(rsp, NETDEV_A_TX_CLK_ACTIVE)) {
+ genlmsg_cancel(rsp, hdr);
+ return -EMSGSIZE;
+ }
+ } else if (enabled < 0) {
+ genlmsg_cancel(rsp, hdr);
+ return -EIO;
+ }
+ }
+
+ genlmsg_end(rsp, hdr);
+
+ return 0;
+}
+
+/**
+ * netdev_nl_tx_clk_get_doit - Handle TX clock get request for a device
+ * Returns all TX clock sources for the specified device.
+ */
+int netdev_nl_tx_clk_get_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ struct netdev_tx_clk_data *clk_data;
+ struct netdev_tx_clk_ref *ref;
+ netdevice_tracker dev_tracker;
+ struct net_device *netdev;
+ u32 ifindex;
+ int err = 0;
+
+ if (!info->attrs[NETDEV_A_TX_CLK_IFINDEX]) {
+ NL_SET_ERR_MSG(info->extack, "Missing device interface index");
+ return -EINVAL;
+ }
+
+ ifindex = nla_get_u32(info->attrs[NETDEV_A_TX_CLK_IFINDEX]);
+ netdev = netdev_get_by_index(genl_info_net(info), ifindex, &dev_tracker,
+ GFP_KERNEL);
+ if (!netdev) {
+ NL_SET_ERR_MSG_FMT(info->extack, "Device with index %u not found", ifindex);
+ return -ENODEV;
+ }
+
+ clk_data = netdev_get_tx_clk_data(netdev);
+ if (!clk_data) {
+ NL_SET_ERR_MSG(info->extack, "Device does not support TX clock control");
+ err = -EOPNOTSUPP;
+ goto err_put_dev;
+ }
+
+ if (!mutex_trylock(&clk_data->lock)) {
+ NL_SET_ERR_MSG(info->extack, "Device TX clock data temporarily unavailable");
+ err = -EBUSY;
+ goto err_put_dev;
+ }
+
+ list_for_each_entry(ref, &clk_data->clk_refs, netdev_list) {
+ struct sk_buff *rsp;
+
+ rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!rsp) {
+ err = -ENOMEM;
+ break;
+ }
+
+ err = netdev_nl_tx_clk_dump_one(rsp, netdev, ref, info);
+ if (err) {
+ nlmsg_free(rsp);
+ if (err == -EIO)
+ NL_SET_ERR_MSG(info->extack, "Failed to query TX clock state");
+ break;
+ }
+
+ err = genlmsg_unicast(genl_info_net(info), rsp,
+ info->snd_portid);
+ if (err)
+ break;
+ }
+
+ mutex_unlock(&clk_data->lock);
+
+err_put_dev:
+ netdev_put(netdev, &dev_tracker);
+ return err;
+}
+
+/**
+ * netdev_nl_tx_clk_get_dumpit - Handle TX clock dump request
+ */
+int netdev_nl_tx_clk_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb);
+ struct net *net = sock_net(skb->sk);
+ struct netdev_tx_clk_data *clk_data;
+ struct netdev_tx_clk_ref *ref;
+ int err = 0;
+
+ for_each_netdev_lock_scoped(net, netdev, ctx->ifindex) {
+ clk_data = netdev_get_tx_clk_data(netdev);
+ if (!clk_data)
+ continue;
+ if (!mutex_trylock(&clk_data->lock))
+ continue;
+ list_for_each_entry(ref, &clk_data->clk_refs, netdev_list)
+ err = netdev_nl_tx_clk_dump_one(skb, netdev,
+ ref,
+ genl_info_dump(cb));
+ mutex_unlock(&clk_data->lock);
+ if (err)
+ break;
+ }
+
+ return err;
+}
+
+/**
+ * netdev_nl_tx_clk_set_doit - Handle TX clock set request
+ */
+int netdev_nl_tx_clk_set_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ struct netdev_tx_clk_ref *ref, *old_active_ref = NULL;
+ struct netdev_tx_clk_data *clk_data;
+ enum netdev_tx_clk_type clk_type;
+ netdevice_tracker dev_tracker;
+ struct net_device *netdev;
+ u32 ifindex;
+ int err;
+
+ if (!info->attrs[NETDEV_A_TX_CLK_IFINDEX] ||
+ !info->attrs[NETDEV_A_TX_CLK_TYPE]) {
+ NL_SET_ERR_MSG(info->extack, "Missing required TX clock parameters");
+ return -EINVAL;
+ }
+
+ ifindex = nla_get_u32(info->attrs[NETDEV_A_TX_CLK_IFINDEX]);
+ clk_type = nla_get_u32(info->attrs[NETDEV_A_TX_CLK_TYPE]);
+
+ netdev = netdev_get_by_index(genl_info_net(info), ifindex, &dev_tracker,
+ GFP_KERNEL);
+ if (!netdev) {
+ NL_SET_ERR_MSG_FMT(info->extack, "Device with index %u not found", ifindex);
+ return -ENODEV;
+ }
+
+ clk_data = netdev_get_tx_clk_data(netdev);
+ if (!clk_data) {
+ NL_SET_ERR_MSG(info->extack, "Device does not support TX clock control");
+ err = -EOPNOTSUPP;
+ goto err_put_dev;
+ }
+
+ if (!mutex_trylock(&clk_data->lock)) {
+ NL_SET_ERR_MSG(info->extack, "Device TX clock data temporarily unavailable");
+ err = -EBUSY;
+ goto err_put_dev;
+ }
+
+ /* Find currently active clock source before making changes */
+ list_for_each_entry(ref, &clk_data->clk_refs, netdev_list) {
+ struct netdev_tx_clk_global_entry *entry = ref->global_entry;
+
+ if (!entry || !entry->ops || !entry->ops->is_enabled)
+ continue;
+ if (entry->ops->is_enabled(ref->priv_data) > 0) {
+ old_active_ref = ref;
+ break;
+ }
+ }
+
+ ref = netdev_find_tx_clk_ref(clk_data, clk_type);
+ if (!ref) {
+ NL_SET_ERR_MSG_FMT(info->extack, "TX clock source (type=%u) not found",
+ clk_type);
+ err = -ENOENT;
+ goto err_unlock;
+ }
+
+ if (old_active_ref && old_active_ref == ref) {
+ mutex_unlock(&clk_data->lock);
+ netdev_put(netdev, &dev_tracker);
+ return 0;
+ }
+
+ err = ref->global_entry->ops->enable(ref->priv_data);
+ if (err) {
+ NL_SET_ERR_MSG_FMT(info->extack, "Failed to enable TX clock source: %d", err);
+ goto err_unlock;
+ }
+
+ mutex_unlock(&clk_data->lock);
+ if (old_active_ref) {
+ struct netdev_tx_clk_global_entry *old_entry =
+ old_active_ref->global_entry;
+
+ netdev_tx_clk_notify_change(netdev, old_entry->key.clk_type,
+ false);
+ }
+ netdev_tx_clk_notify_change(netdev, clk_type, true);
+ netdev_put(netdev, &dev_tracker);
+
+ return 0;
+err_unlock:
+ mutex_unlock(&clk_data->lock);
+err_put_dev:
+ netdev_put(netdev, &dev_tracker);
+ return err;
+}
+
+#else /* CONFIG_NET_TX_CLK */
+int netdev_nl_tx_clk_get_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ return -EOPNOTSUPP;
+}
+
+int netdev_nl_tx_clk_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ return -EOPNOTSUPP;
+}
+
+int netdev_nl_tx_clk_set_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_NET_TX_CLK */
+
subsys_initcall(netdev_genl_init);
diff --git a/net/core/tx_clk.c b/net/core/tx_clk.c
new file mode 100644
index 000000000000..587b876d7c2c
--- /dev/null
+++ b/net/core/tx_clk.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/netdevice.h>
+#include <linux/netdev_tx_clk.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/kref.h>
+#include <linux/slab.h>
+#include <linux/jhash.h>
+#include <linux/jhash.h>
+#include "tx_clk.h"
+
+/* Global TX clock registry protected by mutex */
+static DEFINE_MUTEX(netdev_tx_clk_registry_lock);
+static LIST_HEAD(netdev_tx_clk_registry);
+
+struct netdev_tx_clk_data *netdev_get_tx_clk_data(struct net_device *ndev)
+{
+ return ndev->tx_clk_data;
+}
+
+static struct netdev_tx_clk_key
+netdev_tx_clk_generate_key(struct pci_dev *pci_dev,
+ enum netdev_tx_clk_type clk_type)
+{
+ struct netdev_tx_clk_key key = {0};
+
+ key.device_serial = pci_get_dsn(pci_dev);
+ key.clk_type = clk_type;
+
+ return key;
+}
+
+static bool netdev_tx_clk_key_equal(const struct netdev_tx_clk_key *a,
+ const struct netdev_tx_clk_key *b)
+{
+ return (a->device_serial == b->device_serial &&
+ a->clk_type == b->clk_type);
+}
+
+static struct netdev_tx_clk_global_entry *
+netdev_tx_clk_find_by_key(const struct netdev_tx_clk_key *key)
+{
+ struct netdev_tx_clk_global_entry *entry;
+
+ list_for_each_entry(entry, &netdev_tx_clk_registry, list) {
+ if (netdev_tx_clk_key_equal(&entry->key, key))
+ return entry;
+ }
+ return NULL;
+}
+
+static void netdev_tx_clk_global_entry_release(struct kref *kref)
+{
+ struct netdev_tx_clk_global_entry *entry =
+ container_of(kref, struct netdev_tx_clk_global_entry, kref);
+
+ list_del(&entry->list);
+ if (entry->pci_dev)
+ pci_dev_put(entry->pci_dev);
+ kfree(entry);
+}
+
+struct netdev_tx_clk_ref *
+netdev_find_tx_clk_ref(struct netdev_tx_clk_data *data,
+ enum netdev_tx_clk_type clk_type)
+{
+ struct netdev_tx_clk_ref *ref;
+
+ if (!data)
+ return NULL;
+
+ list_for_each_entry(ref, &data->clk_refs, netdev_list) {
+ if (ref->global_entry->key.clk_type == clk_type)
+ return ref;
+ }
+ return NULL;
+}
+
+/**
+ * netdev_tx_clk_register - register a TX clock source
+ * @ndev: network device
+ * @clk_type: type of clock
+ * @ops: clock operations
+ * @priv_data: driver private data
+ *
+ * Registers a TX clock source, generating a system-unique ID based on the
+ * PCI device information. Multiple network functions can share the same
+ * physical clock if they belong to the same PCI device.
+ */
+int netdev_tx_clk_register(struct net_device *ndev,
+ enum netdev_tx_clk_type clk_type,
+ const struct netdev_tx_clk_ops *ops, void *priv_data)
+{
+ struct netdev_tx_clk_global_entry *global_entry;
+ struct netdev_tx_clk_data *clk_data;
+ struct netdev_tx_clk_key clk_key;
+ struct pci_dev *pci_dev = NULL;
+ struct netdev_tx_clk_ref *ref;
+ int err;
+
+ if (!ndev || !ops)
+ return -EINVAL;
+ if (ndev->dev.parent && ndev->dev.parent->bus == &pci_bus_type)
+ pci_dev = to_pci_dev(ndev->dev.parent);
+ if (!pci_dev)
+ return -EINVAL;
+
+ clk_key = netdev_tx_clk_generate_key(pci_dev, clk_type);
+ mutex_lock(&netdev_tx_clk_registry_lock);
+ global_entry = netdev_tx_clk_find_by_key(&clk_key);
+ if (!global_entry) {
+ global_entry = kzalloc(sizeof(*global_entry), GFP_KERNEL);
+ if (!global_entry) {
+ err = -ENOMEM;
+ goto err_unlock_registry;
+ }
+
+ global_entry->key = clk_key;
+ global_entry->pci_dev = pci_dev ? pci_dev_get(pci_dev) : NULL;
+ global_entry->ops = ops;
+ INIT_LIST_HEAD(&global_entry->netdev_refs);
+ kref_init(&global_entry->kref);
+
+ list_add_tail(&global_entry->list, &netdev_tx_clk_registry);
+ } else {
+ kref_get(&global_entry->kref);
+ }
+ mutex_unlock(&netdev_tx_clk_registry_lock);
+
+ clk_data = netdev_get_tx_clk_data(ndev);
+ if (!clk_data) {
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data) {
+ err = -ENOMEM;
+ goto err_put_global;
+ }
+
+ INIT_LIST_HEAD(&clk_data->clk_refs);
+ mutex_init(&clk_data->lock);
+ ndev->tx_clk_data = clk_data;
+ }
+
+ ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+ if (!ref) {
+ err = -ENOMEM;
+ goto err_put_global;
+ }
+
+ ref->global_entry = global_entry;
+ ref->netdev = ndev;
+ ref->priv_data = priv_data;
+
+ mutex_lock(&clk_data->lock);
+ list_add_tail(&ref->netdev_list, &clk_data->clk_refs);
+ mutex_unlock(&clk_data->lock);
+
+ mutex_lock(&netdev_tx_clk_registry_lock);
+ list_add_tail(&ref->global_list, &global_entry->netdev_refs);
+ mutex_unlock(&netdev_tx_clk_registry_lock);
+
+ return 0;
+
+err_put_global:
+ mutex_lock(&netdev_tx_clk_registry_lock);
+ kref_put(&global_entry->kref, netdev_tx_clk_global_entry_release);
+err_unlock_registry:
+ mutex_unlock(&netdev_tx_clk_registry_lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(netdev_tx_clk_register);
+
+/**
+ * netdev_tx_clk_unregister - Unregister a specific TX clock
+ * @ndev: network device
+ * @clk_type: type of clock to unregister
+ */
+void netdev_tx_clk_unregister(struct net_device *ndev,
+ enum netdev_tx_clk_type clk_type)
+{
+ struct netdev_tx_clk_data *clk_data;
+ struct netdev_tx_clk_ref *ref;
+
+ clk_data = netdev_get_tx_clk_data(ndev);
+ if (!clk_data)
+ return;
+
+ mutex_lock(&clk_data->lock);
+
+ ref = netdev_find_tx_clk_ref(clk_data, clk_type);
+ if (ref) {
+ struct netdev_tx_clk_global_entry *global_entry =
+ ref->global_entry;
+
+ /* Remove from netdev list */
+ list_del(&ref->netdev_list);
+
+ /* Remove from global entry list and put reference */
+ mutex_lock(&netdev_tx_clk_registry_lock);
+ list_del(&ref->global_list);
+ kref_put(&global_entry->kref,
+ netdev_tx_clk_global_entry_release);
+ mutex_unlock(&netdev_tx_clk_registry_lock);
+
+ kfree(ref);
+ }
+
+ /* Clean up clk_data if no more refs */
+ if (list_empty(&clk_data->clk_refs)) {
+ mutex_unlock(&clk_data->lock);
+ kfree(clk_data);
+ ndev->tx_clk_data = NULL;
+ } else {
+ mutex_unlock(&clk_data->lock);
+ }
+}
+EXPORT_SYMBOL_GPL(netdev_tx_clk_unregister);
diff --git a/net/core/tx_clk.h b/net/core/tx_clk.h
new file mode 100644
index 000000000000..6374e0cb6c64
--- /dev/null
+++ b/net/core/tx_clk.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * netdev_tx_clk.h - allow net_device TX clock control
+ * Author: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
+ */
+#ifndef _NET_TX_CLK_H
+#define _NET_TX_CLK_H
+
+struct netdev_tx_clk_key {
+ u64 device_serial;
+ enum netdev_tx_clk_type clk_type;
+};
+
+struct netdev_tx_clk_global_entry {
+ struct list_head list;
+ struct list_head netdev_refs;
+ struct netdev_tx_clk_key key;
+ struct pci_dev *pci_dev;
+ const struct netdev_tx_clk_ops *ops;
+ struct kref kref;
+};
+
+struct netdev_tx_clk_ref {
+ struct list_head netdev_list;
+ struct list_head global_list;
+ struct netdev_tx_clk_global_entry *global_entry;
+ struct net_device *netdev;
+ void *priv_data;
+};
+
+struct netdev_tx_clk_data {
+ struct list_head clk_refs;
+ struct mutex lock; /* per clock access protection */
+};
+
+#endif /* _NET_TX_CLK_H */
diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h
index 48eb49aa03d4..e7ff67474246 100644
--- a/tools/include/uapi/linux/netdev.h
+++ b/tools/include/uapi/linux/netdev.h
@@ -82,6 +82,12 @@ enum netdev_napi_threaded {
NETDEV_NAPI_THREADED_ENABLED,
};
+enum netdev_tx_clk_type {
+ NETDEV_TX_CLK_TYPE_OCXO,
+ NETDEV_TX_CLK_TYPE_EXT_REF,
+ NETDEV_TX_CLK_TYPE_SYNCE,
+};
+
enum {
NETDEV_A_DEV_IFINDEX = 1,
NETDEV_A_DEV_PAD,
@@ -210,6 +216,15 @@ enum {
NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1)
};
+enum {
+ NETDEV_A_TX_CLK_IFINDEX = 1,
+ NETDEV_A_TX_CLK_TYPE,
+ NETDEV_A_TX_CLK_ACTIVE,
+
+ __NETDEV_A_TX_CLK_MAX,
+ NETDEV_A_TX_CLK_MAX = (__NETDEV_A_TX_CLK_MAX - 1)
+};
+
enum {
NETDEV_CMD_DEV_GET = 1,
NETDEV_CMD_DEV_ADD_NTF,
@@ -226,6 +241,9 @@ enum {
NETDEV_CMD_BIND_RX,
NETDEV_CMD_NAPI_SET,
NETDEV_CMD_BIND_TX,
+ NETDEV_CMD_TX_CLK_GET,
+ NETDEV_CMD_TX_CLK_SET,
+ NETDEV_CMD_TX_CLK_CHANGE_NTF,
__NETDEV_CMD_MAX,
NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
--
2.38.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-28 16:43 [RFC PATCH v2] net: add net-device TX clock source selection framework Arkadiusz Kubalewski
@ 2025-08-28 16:57 ` Mina Almasry
2025-08-29 7:05 ` Kubalewski, Arkadiusz
2025-08-28 17:06 ` Andrew Lunn
2025-08-28 22:31 ` Jakub Kicinski
2 siblings, 1 reply; 10+ messages in thread
From: Mina Almasry @ 2025-08-28 16:57 UTC (permalink / raw)
To: Arkadiusz Kubalewski
Cc: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
edumazet, kuba, pabeni, horms, sdf, asml.silence, leitao, kuniyu,
jiri, aleksandr.loktionov, ivecera, linux-kernel, intel-wired-lan,
netdev
On Thu, Aug 28, 2025 at 9:50 AM Arkadiusz Kubalewski
<arkadiusz.kubalewski@intel.com> wrote:
> ---
> Documentation/netlink/specs/netdev.yaml | 61 +++++
> drivers/net/ethernet/intel/ice/Makefile | 1 +
> drivers/net/ethernet/intel/ice/ice.h | 5 +
> drivers/net/ethernet/intel/ice/ice_lib.c | 6 +
> drivers/net/ethernet/intel/ice/ice_main.c | 6 +
> drivers/net/ethernet/intel/ice/ice_tx_clk.c | 100 +++++++
> drivers/net/ethernet/intel/ice/ice_tx_clk.h | 17 ++
> include/linux/netdev_tx_clk.h | 92 +++++++
> include/linux/netdevice.h | 4 +
> include/uapi/linux/netdev.h | 18 ++
> net/Kconfig | 21 ++
> net/core/Makefile | 1 +
> net/core/netdev-genl-gen.c | 37 +++
> net/core/netdev-genl-gen.h | 4 +
> net/core/netdev-genl.c | 287 ++++++++++++++++++++
> net/core/tx_clk.c | 218 +++++++++++++++
> net/core/tx_clk.h | 36 +++
> tools/include/uapi/linux/netdev.h | 18 ++
> 18 files changed, 932 insertions(+)
Consider breaking up a change of this size in a patch series to make
it a bit easier for reviewers, if it makes sense to you.
--
Thanks,
Mina
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-28 16:57 ` Mina Almasry
@ 2025-08-29 7:05 ` Kubalewski, Arkadiusz
0 siblings, 0 replies; 10+ messages in thread
From: Kubalewski, Arkadiusz @ 2025-08-29 7:05 UTC (permalink / raw)
To: Mina Almasry
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org, sdf@fomichev.me,
asml.silence@gmail.com, leitao@debian.org, kuniyu@google.com,
jiri@resnulli.us, Loktionov, Aleksandr, Vecera, Ivan,
linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
netdev@vger.kernel.org
>From: Mina Almasry <almasrymina@google.com>
>Sent: Thursday, August 28, 2025 6:58 PM
>
>On Thu, Aug 28, 2025 at 9:50 AM Arkadiusz Kubalewski
><arkadiusz.kubalewski@intel.com> wrote:
>> ---
>> Documentation/netlink/specs/netdev.yaml | 61 +++++
>> drivers/net/ethernet/intel/ice/Makefile | 1 +
>> drivers/net/ethernet/intel/ice/ice.h | 5 +
>> drivers/net/ethernet/intel/ice/ice_lib.c | 6 +
>> drivers/net/ethernet/intel/ice/ice_main.c | 6 +
>> drivers/net/ethernet/intel/ice/ice_tx_clk.c | 100 +++++++
>> drivers/net/ethernet/intel/ice/ice_tx_clk.h | 17 ++
>> include/linux/netdev_tx_clk.h | 92 +++++++
>> include/linux/netdevice.h | 4 +
>> include/uapi/linux/netdev.h | 18 ++
>> net/Kconfig | 21 ++
>> net/core/Makefile | 1 +
>> net/core/netdev-genl-gen.c | 37 +++
>> net/core/netdev-genl-gen.h | 4 +
>> net/core/netdev-genl.c | 287 ++++++++++++++++++++
>> net/core/tx_clk.c | 218 +++++++++++++++
>> net/core/tx_clk.h | 36 +++
>> tools/include/uapi/linux/netdev.h | 18 ++
>> 18 files changed, 932 insertions(+)
>
>Consider breaking up a change of this size in a patch series to make it a
>bit easier for reviewers, if it makes sense to you.
>
>--
>Thanks,
>Mina
Yes, will surely do for non-RFC submission.
Thank you!
Arkadiusz
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-28 16:43 [RFC PATCH v2] net: add net-device TX clock source selection framework Arkadiusz Kubalewski
2025-08-28 16:57 ` Mina Almasry
@ 2025-08-28 17:06 ` Andrew Lunn
2025-08-29 7:05 ` Kubalewski, Arkadiusz
2025-08-28 22:31 ` Jakub Kicinski
2 siblings, 1 reply; 10+ messages in thread
From: Andrew Lunn @ 2025-08-28 17:06 UTC (permalink / raw)
To: Arkadiusz Kubalewski
Cc: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
edumazet, kuba, pabeni, horms, sdf, almasrymina, asml.silence,
leitao, kuniyu, jiri, aleksandr.loktionov, ivecera, linux-kernel,
intel-wired-lan, netdev
> - use netlink instead of sysfs
ethtool is netlink. Why is this not part of the ethtool API?
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-28 17:06 ` Andrew Lunn
@ 2025-08-29 7:05 ` Kubalewski, Arkadiusz
0 siblings, 0 replies; 10+ messages in thread
From: Kubalewski, Arkadiusz @ 2025-08-29 7:05 UTC (permalink / raw)
To: Andrew Lunn
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org, sdf@fomichev.me,
almasrymina@google.com, asml.silence@gmail.com, leitao@debian.org,
kuniyu@google.com, jiri@resnulli.us, Loktionov, Aleksandr,
Vecera, Ivan, linux-kernel@vger.kernel.org,
intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org
>From: Andrew Lunn <andrew@lunn.ch>
>Sent: Thursday, August 28, 2025 7:07 PM
>
>> - use netlink instead of sysfs
>
>ethtool is netlink. Why is this not part of the ethtool API?
>
> Andrew
Yes, sure, will extend for non-RFC submission.
Thank you!
Arkadiusz
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-28 16:43 [RFC PATCH v2] net: add net-device TX clock source selection framework Arkadiusz Kubalewski
2025-08-28 16:57 ` Mina Almasry
2025-08-28 17:06 ` Andrew Lunn
@ 2025-08-28 22:31 ` Jakub Kicinski
2025-08-29 7:49 ` Kubalewski, Arkadiusz
2 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2025-08-28 22:31 UTC (permalink / raw)
To: Arkadiusz Kubalewski
Cc: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
edumazet, pabeni, horms, sdf, almasrymina, asml.silence, leitao,
kuniyu, jiri, aleksandr.loktionov, ivecera, linux-kernel,
intel-wired-lan, netdev
On Thu, 28 Aug 2025 18:43:45 +0200 Arkadiusz Kubalewski wrote:
> Add support for user-space control over network device transmit clock
> sources through a new extended netdevice netlink interface.
> A network device may support multiple TX clock sources (OCXO, SyncE
> reference, external reference clocks) which are critical for
> time-sensitive networking applications and synchronization protocols.
how does this relate to the dpll pin in rtnetlink then?
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-28 22:31 ` Jakub Kicinski
@ 2025-08-29 7:49 ` Kubalewski, Arkadiusz
2025-08-30 0:34 ` Jakub Kicinski
0 siblings, 1 reply; 10+ messages in thread
From: Kubalewski, Arkadiusz @ 2025-08-29 7:49 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
horms@kernel.org, sdf@fomichev.me, almasrymina@google.com,
asml.silence@gmail.com, leitao@debian.org, kuniyu@google.com,
jiri@resnulli.us, Loktionov, Aleksandr, Vecera, Ivan,
linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
netdev@vger.kernel.org
>From: Jakub Kicinski <kuba@kernel.org>
>Sent: Friday, August 29, 2025 12:32 AM
>
>On Thu, 28 Aug 2025 18:43:45 +0200 Arkadiusz Kubalewski wrote:
>> Add support for user-space control over network device transmit clock
>> sources through a new extended netdevice netlink interface.
>> A network device may support multiple TX clock sources (OCXO, SyncE
>> reference, external reference clocks) which are critical for
>> time-sensitive networking applications and synchronization protocols.
>
>how does this relate to the dpll pin in rtnetlink then?
In general it doesn't directly. However we could see indirect relation
due to possible DPLL existence in the equation.
The rtnetlink pin was related to feeding the dpll with the signal,
here is the other way around, by feeding the phy TX of given interface
with user selected clock source signal.
Previously if our E810 EEC products with DPLL, all the ports had their
phy TX fed with the clock signal generated by DPLL.
For E830 the user is able to select if the signal is provided from: the
EEC DPLL(SyncE), provided externally(ext_ref), or OCXO.
I assume your suggestion to extend rtnetlink instead of netdev-netlink?
Thank you!
Arkadiusz
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-29 7:49 ` Kubalewski, Arkadiusz
@ 2025-08-30 0:34 ` Jakub Kicinski
2025-09-05 11:14 ` Kubalewski, Arkadiusz
0 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2025-08-30 0:34 UTC (permalink / raw)
To: Kubalewski, Arkadiusz
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
horms@kernel.org, sdf@fomichev.me, almasrymina@google.com,
asml.silence@gmail.com, leitao@debian.org, kuniyu@google.com,
jiri@resnulli.us, Loktionov, Aleksandr, Vecera, Ivan,
linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
netdev@vger.kernel.org
On Fri, 29 Aug 2025 07:49:46 +0000 Kubalewski, Arkadiusz wrote:
> >From: Jakub Kicinski <kuba@kernel.org>
> >Sent: Friday, August 29, 2025 12:32 AM
> >
> >On Thu, 28 Aug 2025 18:43:45 +0200 Arkadiusz Kubalewski wrote:
> >> Add support for user-space control over network device transmit clock
> >> sources through a new extended netdevice netlink interface.
> >> A network device may support multiple TX clock sources (OCXO, SyncE
> >> reference, external reference clocks) which are critical for
> >> time-sensitive networking applications and synchronization protocols.
> >
> >how does this relate to the dpll pin in rtnetlink then?
>
> In general it doesn't directly. However we could see indirect relation
> due to possible DPLL existence in the equation.
>
> The rtnetlink pin was related to feeding the dpll with the signal,
> here is the other way around, by feeding the phy TX of given interface
> with user selected clock source signal.
>
> Previously if our E810 EEC products with DPLL, all the ports had their
> phy TX fed with the clock signal generated by DPLL.
> For E830 the user is able to select if the signal is provided from: the
> EEC DPLL(SyncE), provided externally(ext_ref), or OCXO.
>
> I assume your suggestion to extend rtnetlink instead of netdev-netlink?
Yes, for sure, but also I'm a little worried about this new API
duplicating the DPLL, just being more "shallow".
What is the "synce" option for example? If I set the Tx clock to SyncE
something is feeding it from another port, presumably selected by FW or
some other tooling?
Similar on ext-ref, there has to be a DPLL somewhere in the path,
in case reference goes away? We assume user knows what "ext-ref" means,
it's not connected to any info within Linux, DPLL or PTP.
OXCO is just an oscillator on the board without a sync. What kind of
XO it is likely an unnecessary detail in the context of "what reference
drives the eth clock".
All of these things may make perfect sense when you look at a
particular product, but for a generic Linux kernel uAPI it does not
feel very natural.
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-08-30 0:34 ` Jakub Kicinski
@ 2025-09-05 11:14 ` Kubalewski, Arkadiusz
2025-09-05 14:09 ` Ivan Vecera
0 siblings, 1 reply; 10+ messages in thread
From: Kubalewski, Arkadiusz @ 2025-09-05 11:14 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
horms@kernel.org, sdf@fomichev.me, almasrymina@google.com,
asml.silence@gmail.com, leitao@debian.org, kuniyu@google.com,
jiri@resnulli.us, Loktionov, Aleksandr, Vecera, Ivan,
linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
netdev@vger.kernel.org
>From: Jakub Kicinski <kuba@kernel.org>
>Sent: Saturday, August 30, 2025 2:34 AM
> On Fri, 29 Aug 2025 07:49:46 +0000 Kubalewski, Arkadiusz wrote:
> > >From: Jakub Kicinski <kuba@kernel.org>
> > >Sent: Friday, August 29, 2025 12:32 AM
> > >
> > >On Thu, 28 Aug 2025 18:43:45 +0200 Arkadiusz Kubalewski wrote:
> > >> Add support for user-space control over network device transmit clock
> > >> sources through a new extended netdevice netlink interface.
> > >> A network device may support multiple TX clock sources (OCXO, SyncE
> > >> reference, external reference clocks) which are critical for
> > >> time-sensitive networking applications and synchronization protocols.
> > >
> > >how does this relate to the dpll pin in rtnetlink then?
> >
> > In general it doesn't directly. However we could see indirect relation
> > due to possible DPLL existence in the equation.
> >
> > The rtnetlink pin was related to feeding the dpll with the signal,
> > here is the other way around, by feeding the phy TX of given interface
> > with user selected clock source signal.
> >
> > Previously if our E810 EEC products with DPLL, all the ports had their
> > phy TX fed with the clock signal generated by DPLL.
> > For E830 the user is able to select if the signal is provided from: the
> > EEC DPLL(SyncE), provided externally(ext_ref), or OCXO.
> >
> > I assume your suggestion to extend rtnetlink instead of netdev-netlink?
>
> Yes, for sure, but also I'm a little worried about this new API
> duplicating the DPLL, just being more "shallow".
>
> What is the "synce" option for example? If I set the Tx clock to SyncE
> something is feeding it from another port, presumably selected by FW or
> some other tooling?
>
In this particular case the "synce" source could point to a DPLL device of EEC
type, and there is a sense to have it together in one API. Like a two pins
registered with a netdev, one is input and it would be used for clock recovery,
second is output - for tx-clk control - either using the DPLL device produced
signal or not. Probably worth to mention this is the case with 'external' DPLL,
where ice driver doesn't control a DPLL device but it could use the output as
is this 'synce' one doing.
> Similar on ext-ref, there has to be a DPLL somewhere in the path,
> in case reference goes away? We assume user knows what "ext-ref" means,
> it's not connected to any info within Linux, DPLL or PTP.
>
Adding control over 'ext-ref' muds up the clean story of above.. The 'ext-ref'
source is rather an external pin, which have to be provided with external
clock signal, not defined anywhere else, or connected directly to DPLL device.
Purely HW/platform dependent. User needs to know the HW connections, the
signal to this pin could be produced with external signal generator, same host
but a different DPLL device, or simply different host and device. There can be
a PLL somewhere between generator and TX PHY but there is no lock status, thus
adding new dpll device just to model this seemed an overshot.
Exactly because of nature of 'ext-ref' decided to go with extending the
net device itself and made it separated from DPLL subsystem.
Please share your thoughts, right now I see two ways forward:
- moving netdev netlink to rt-netlink,
- kind of hacking into dpll subsystem with 'ext-ref' and output netdev pin.
> OXCO is just an oscillator on the board without a sync. What kind of
> XO it is likely an unnecessary detail in the context of "what reference
> drives the eth clock".
>
I agree this could be hidden, unless there is user case for selecting one
from multiple available in the OS.
> All of these things may make perfect sense when you look at a
> particular product, but for a generic Linux kernel uAPI it does not
> feel very natural.
>
Yeah, I like generic, but after all we are all HW dependent.
Thank you!
Arkadiusz
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2] net: add net-device TX clock source selection framework
2025-09-05 11:14 ` Kubalewski, Arkadiusz
@ 2025-09-05 14:09 ` Ivan Vecera
0 siblings, 0 replies; 10+ messages in thread
From: Ivan Vecera @ 2025-09-05 14:09 UTC (permalink / raw)
To: Kubalewski, Arkadiusz, Jakub Kicinski
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
horms@kernel.org, sdf@fomichev.me, almasrymina@google.com,
asml.silence@gmail.com, leitao@debian.org, kuniyu@google.com,
jiri@resnulli.us, Loktionov, Aleksandr,
linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
netdev@vger.kernel.org, Rob Herring
On 05. 09. 25 1:14 odp., Kubalewski, Arkadiusz wrote:
>> From: Jakub Kicinski <kuba@kernel.org>
>> Sent: Saturday, August 30, 2025 2:34 AM
>> On Fri, 29 Aug 2025 07:49:46 +0000 Kubalewski, Arkadiusz wrote:
>>>> From: Jakub Kicinski <kuba@kernel.org>
>>>> Sent: Friday, August 29, 2025 12:32 AM
>>>>
>>>> On Thu, 28 Aug 2025 18:43:45 +0200 Arkadiusz Kubalewski wrote:
>>>>> Add support for user-space control over network device transmit clock
>>>>> sources through a new extended netdevice netlink interface.
>>>>> A network device may support multiple TX clock sources (OCXO, SyncE
>>>>> reference, external reference clocks) which are critical for
>>>>> time-sensitive networking applications and synchronization protocols.
>>>>
>>>> how does this relate to the dpll pin in rtnetlink then?
>>>
>>> In general it doesn't directly. However we could see indirect relation
>>> due to possible DPLL existence in the equation.
>>>
>>> The rtnetlink pin was related to feeding the dpll with the signal,
>>> here is the other way around, by feeding the phy TX of given interface
>>> with user selected clock source signal.
>>>
>>> Previously if our E810 EEC products with DPLL, all the ports had their
>>> phy TX fed with the clock signal generated by DPLL.
>>> For E830 the user is able to select if the signal is provided from: the
>>> EEC DPLL(SyncE), provided externally(ext_ref), or OCXO.
>>>
>>> I assume your suggestion to extend rtnetlink instead of netdev-netlink?
>>
>> Yes, for sure, but also I'm a little worried about this new API
>> duplicating the DPLL, just being more "shallow".
>>
>> What is the "synce" option for example? If I set the Tx clock to SyncE
>> something is feeding it from another port, presumably selected by FW or
>> some other tooling?
>>
>
> In this particular case the "synce" source could point to a DPLL device of EEC
> type, and there is a sense to have it together in one API. Like a two pins
> registered with a netdev, one is input and it would be used for clock recovery,
> second is output - for tx-clk control - either using the DPLL device produced
> signal or not. Probably worth to mention this is the case with 'external' DPLL,
> where ice driver doesn't control a DPLL device but it could use the output as
> is this 'synce' one doing.
Yes, this simply describes a diagram I described in my DT RFC [1] that
defines relationship between DPLL device and network card.
+-----------+
+--| NIC 1 |<-+
| +-----------+ |
| |
| RxCLK TxCLK |
| |
| +-----------+ |
+->| channel 1 |--+
+------+ |-- DPLL ---|
| GNSS |---------->| channel 2 |--+
+------+ RefCLK +-----------+ |
|
TxCLK |
|
+-----------+ |
| NIC 2 |<-+
+-----------+
Here we have 2 scenarios... The first (NIC1) is a SyncE one where NIC1
feeds some DPLL input reference with recovered clock and consumes the
synchronized signal from the DPLL output pin as Tx clock. In the second
(NIC2) case the NIC uses some DPLL output pin signal as Tx clock and
the DPLL is synchronized with some external source.
If I understand well your comment, the RxCLK above is the dpll_pin
currently present in net_device. The TxCLK for the first case (NIC1)
should be the dpll_pin you are calling as "synce" source. And TxCLK for
the second case (NIC2) should be the dpll_pin you are calling "ext-ref".
Is it correct?
If so there should be another dpll_pin in the net_device let's call it
tx_dpll_pin... The existing one should be some input pin of some DPLL
device and the tx_dpll_pin should be some output pin of that device.
A user could set the tx_dpll_pin by ip link command like:
# ip link set eth0 txclk <dpll-pin-id>
[1]
https://patchwork.kernel.org/project/netdevbpf/patch/20250815144736.1438060-1-ivecera@redhat.com/
>> Similar on ext-ref, there has to be a DPLL somewhere in the path,
>> in case reference goes away? We assume user knows what "ext-ref" means,
>> it's not connected to any info within Linux, DPLL or PTP.
>>
>
> Adding control over 'ext-ref' muds up the clean story of above.. The 'ext-ref'
> source is rather an external pin, which have to be provided with external
> clock signal, not defined anywhere else, or connected directly to DPLL device.
> Purely HW/platform dependent. User needs to know the HW connections, the
> signal to this pin could be produced with external signal generator, same host
> but a different DPLL device, or simply different host and device. There can be
> a PLL somewhere between generator and TX PHY but there is no lock status, thus
> adding new dpll device just to model this seemed an overshot.
>
> Exactly because of nature of 'ext-ref' decided to go with extending the
> net device itself and made it separated from DPLL subsystem.
>
> Please share your thoughts, right now I see two ways forward:
> - moving netdev netlink to rt-netlink,
> - kind of hacking into dpll subsystem with 'ext-ref' and output netdev pin.
You are mentioning above the case where an external DPLL device that is
not under control of network driver (e.g. DPLL chip on motherboard and
some LOM NIC). In this case is currently impossible for the NIC driver
to report dpll_pin used for recovered clock as it does not control the
DPLL device and all dpll_devices and dpll_pins are registered by the
different driver.
There could be defined some DT schema for the relations between ethernet
controller and used DPLL device. Then the system firmware (DT/ACPI...)
could provide the wiring info (e.g. DPLL pin REF0P is used for recovered
clock from NIC1 and output pin OUT4P for the Tx clock by NIC1 etc.)
...and also there should be some DPLL API for the drivers that would
allow to access DPLL devices and pins. E.g. NIC driver reads from its
fwnode that possible tx-clock pins could be out_pin1, 3, 5 but it needs
to translate fwnode_handles of these pins to registered DPLL pin IDs.
Thanks,
Ivan
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-09-05 14:10 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-28 16:43 [RFC PATCH v2] net: add net-device TX clock source selection framework Arkadiusz Kubalewski
2025-08-28 16:57 ` Mina Almasry
2025-08-29 7:05 ` Kubalewski, Arkadiusz
2025-08-28 17:06 ` Andrew Lunn
2025-08-29 7:05 ` Kubalewski, Arkadiusz
2025-08-28 22:31 ` Jakub Kicinski
2025-08-29 7:49 ` Kubalewski, Arkadiusz
2025-08-30 0:34 ` Jakub Kicinski
2025-09-05 11:14 ` Kubalewski, Arkadiusz
2025-09-05 14:09 ` Ivan Vecera
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).