* [PATCH v5 net-next 15/15] net: dsa: netc: add support for ethtool private statistics
From: Wei Fang @ 2026-04-30 2:49 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, robh, krzk+dt, conor+dt,
f.fainelli, frank.li, chleroy, horms, linux
Cc: netdev, linux-kernel, devicetree, linuxppc-dev, linux-arm-kernel,
imx
In-Reply-To: <20260430024945.3413973-1-wei.fang@nxp.com>
Implement the ethtool private statistics interface to expose additional
port-level and MAC-level counters that are not covered by the standard
IEEE 802.3 statistics. The pMAC counters are only reported when the port
supports Frame Preemption (802.1Qbu/802.3br).
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/dsa/netc/netc_ethtool.c | 107 ++++++++++++++++++++++++++
drivers/net/dsa/netc/netc_main.c | 3 +
drivers/net/dsa/netc/netc_switch.h | 9 +++
drivers/net/dsa/netc/netc_switch_hw.h | 58 ++++++++++++++
4 files changed, 177 insertions(+)
diff --git a/drivers/net/dsa/netc/netc_ethtool.c b/drivers/net/dsa/netc/netc_ethtool.c
index ac8940b5a85c..8d04db534347 100644
--- a/drivers/net/dsa/netc/netc_ethtool.c
+++ b/drivers/net/dsa/netc/netc_ethtool.c
@@ -19,6 +19,56 @@ static const struct ethtool_rmon_hist_range netc_rmon_ranges[] = {
{ }
};
+static const struct netc_port_stat netc_port_counters[] = {
+ { NETC_PTGSLACR, "port gate late arrival frames" },
+ { NETC_PSDFTCR, "port SDF transmit frames" },
+ { NETC_PSDFDDCR, "port SDF drop duplicate frames" },
+ { NETC_PRXDCR, "port rx discard frames" },
+ { NETC_PRXDCRRR, "port rx discard read-reset" },
+ { NETC_PRXDCRR0, "port rx discard reason 0" },
+ { NETC_PRXDCRR1, "port rx discard reason 1" },
+ { NETC_PTXDCR, "port tx discard frames" },
+ { NETC_PTXDCRRR, "port tx discard read-reset" },
+ { NETC_PTXDCRR0, "port tx discard reason 0" },
+ { NETC_PTXDCRR1, "port tx discard reason 1" },
+ { NETC_BPDCR, "bridge port discard frames" },
+ { NETC_BPDCRRR, "bridge port discard read-reset" },
+ { NETC_BPDCRR0, "bridge port discard reason 0" },
+ { NETC_BPDCRR1, "bridge port discard reason 1" },
+};
+
+static const struct netc_port_stat netc_emac_counters[] = {
+ { NETC_PM_ROCT(0), "eMAC rx octets" },
+ { NETC_PM_RVLAN(0), "eMAC rx VLAN frames" },
+ { NETC_PM_RERR(0), "eMAC rx frame errors" },
+ { NETC_PM_RUCA(0), "eMAC rx unicast frames" },
+ { NETC_PM_RDRP(0), "eMAC rx dropped packets" },
+ { NETC_PM_RPKT(0), "eMAC rx packets" },
+ { NETC_PM_TOCT(0), "eMAC tx octets" },
+ { NETC_PM_TVLAN(0), "eMAC tx VLAN frames" },
+ { NETC_PM_TFCS(0), "eMAC tx FCS errors" },
+ { NETC_PM_TUCA(0), "eMAC tx unicast frames" },
+ { NETC_PM_TPKT(0), "eMAC tx packets" },
+ { NETC_PM_TUND(0), "eMAC tx undersized packets" },
+ { NETC_PM_TIOCT(0), "eMAC tx invalid octets" },
+};
+
+static const struct netc_port_stat netc_pmac_counters[] = {
+ { NETC_PM_ROCT(1), "pMAC rx octets" },
+ { NETC_PM_RVLAN(1), "pMAC rx VLAN frames" },
+ { NETC_PM_RERR(1), "pMAC rx frame errors" },
+ { NETC_PM_RUCA(1), "pMAC rx unicast frames" },
+ { NETC_PM_RDRP(1), "pMAC rx dropped packets" },
+ { NETC_PM_RPKT(1), "pMAC rx packets" },
+ { NETC_PM_TOCT(1), "pMAC tx octets" },
+ { NETC_PM_TVLAN(1), "pMAC tx VLAN frames" },
+ { NETC_PM_TFCS(1), "pMAC tx FCS errors" },
+ { NETC_PM_TUCA(1), "pMAC tx unicast frames" },
+ { NETC_PM_TPKT(1), "pMAC tx packets" },
+ { NETC_PM_TUND(1), "pMAC tx undersized packets" },
+ { NETC_PM_TIOCT(1), "pMAC tx invalid octets" },
+};
+
static void netc_port_pause_stats(struct netc_port *np, int mac,
struct ethtool_pause_stats *stats)
{
@@ -188,3 +238,60 @@ void netc_port_get_eth_mac_stats(struct dsa_switch *ds, int port,
break;
}
}
+
+int netc_port_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+ struct netc_port *np = NETC_PORT(ds, port);
+ int size;
+
+ if (sset != ETH_SS_STATS)
+ return -EOPNOTSUPP;
+
+ size = ARRAY_SIZE(netc_port_counters) +
+ ARRAY_SIZE(netc_emac_counters);
+
+ if (np->caps.pmac)
+ size += ARRAY_SIZE(netc_pmac_counters);
+
+ return size;
+}
+
+void netc_port_get_strings(struct dsa_switch *ds, int port,
+ u32 sset, u8 *data)
+{
+ struct netc_port *np = NETC_PORT(ds, port);
+ int i;
+
+ if (sset != ETH_SS_STATS)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(netc_port_counters); i++)
+ ethtool_cpy(&data, netc_port_counters[i].name);
+
+ for (i = 0; i < ARRAY_SIZE(netc_emac_counters); i++)
+ ethtool_cpy(&data, netc_emac_counters[i].name);
+
+ if (!np->caps.pmac)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(netc_pmac_counters); i++)
+ ethtool_cpy(&data, netc_pmac_counters[i].name);
+}
+
+void netc_port_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
+{
+ struct netc_port *np = NETC_PORT(ds, port);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(netc_port_counters); i++)
+ *data++ = netc_port_rd(np, netc_port_counters[i].reg);
+
+ for (i = 0; i < ARRAY_SIZE(netc_emac_counters); i++)
+ *data++ = netc_port_rd64(np, netc_emac_counters[i].reg);
+
+ if (!np->caps.pmac)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(netc_pmac_counters); i++)
+ *data++ = netc_port_rd64(np, netc_pmac_counters[i].reg);
+}
diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c
index ae8f28b82b72..803582d939b0 100644
--- a/drivers/net/dsa/netc/netc_main.c
+++ b/drivers/net/dsa/netc/netc_main.c
@@ -1472,6 +1472,9 @@ static const struct dsa_switch_ops netc_switch_ops = {
.get_rmon_stats = netc_port_get_rmon_stats,
.get_eth_ctrl_stats = netc_port_get_eth_ctrl_stats,
.get_eth_mac_stats = netc_port_get_eth_mac_stats,
+ .get_sset_count = netc_port_get_sset_count,
+ .get_strings = netc_port_get_strings,
+ .get_ethtool_stats = netc_port_get_ethtool_stats,
};
static int netc_switch_probe(struct pci_dev *pdev,
diff --git a/drivers/net/dsa/netc/netc_switch.h b/drivers/net/dsa/netc/netc_switch.h
index d477b0cd2157..90d750331fb9 100644
--- a/drivers/net/dsa/netc/netc_switch.h
+++ b/drivers/net/dsa/netc/netc_switch.h
@@ -93,6 +93,11 @@ struct netc_fdb_entry {
struct hlist_node node;
};
+struct netc_port_stat {
+ int reg;
+ char name[ETH_GSTRING_LEN] __nonstring;
+};
+
struct netc_switch {
struct pci_dev *pdev;
struct device *dev;
@@ -159,5 +164,9 @@ void netc_port_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
struct ethtool_eth_ctrl_stats *ctrl_stats);
void netc_port_get_eth_mac_stats(struct dsa_switch *ds, int port,
struct ethtool_eth_mac_stats *mac_stats);
+int netc_port_get_sset_count(struct dsa_switch *ds, int port, int sset);
+void netc_port_get_strings(struct dsa_switch *ds, int port,
+ u32 sset, u8 *data);
+void netc_port_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data);
#endif
diff --git a/drivers/net/dsa/netc/netc_switch_hw.h b/drivers/net/dsa/netc/netc_switch_hw.h
index f8d436ad9623..1b016e7dd03e 100644
--- a/drivers/net/dsa/netc/netc_switch_hw.h
+++ b/drivers/net/dsa/netc/netc_switch_hw.h
@@ -87,6 +87,17 @@
#define PSR_TX_BUSY BIT(0)
#define PSR_RX_BUSY BIT(1)
+#define NETC_PTGSLACR 0x130
+
+#define NETC_PRXDCR 0x1c0
+#define NETC_PRXDCRRR 0x1c4
+#define NETC_PRXDCRR0 0x1c8
+#define NETC_PRXDCRR1 0x1cc
+#define NETC_PTXDCR 0x1e0
+#define NETC_PTXDCRRR 0x1e4
+#define NETC_PTXDCRR0 0x1e8
+#define NETC_PTXDCRR1 0x1ec
+
#define NETC_PTCTMSDUR(a) (0x208 + (a) * 0x20)
#define PTCTMSDUR_MAXSDU GENMASK(15, 0)
#define PTCTMSDUR_SDU_TYPE GENMASK(17, 16)
@@ -94,6 +105,9 @@
#define SDU_TYPE_MPDU 1
#define SDU_TYPE_MSDU 2
+#define NETC_PSDFTCR 0x4c4
+#define NETC_PSDFDDCR 0x4c8
+
#define NETC_BPCR 0x500
#define BPCR_DYN_LIMIT GENMASK(15, 0)
#define BPCR_MLO GENMASK(22, 20)
@@ -142,6 +156,11 @@ enum netc_stg_stage {
NETC_STG_STATE_FORWARDING,
};
+#define NETC_BPDCR 0x580
+#define NETC_BPDCRRR 0x584
+#define NETC_BPDCRR0 0x588
+#define NETC_BPDCRR1 0x58c
+
/* Definition of Switch ethernet MAC port registers */
#define NETC_PMAC_OFFSET 0x400
#define NETC_PM_CMD_CFG(a) (0x1008 + (a) * 0x400)
@@ -176,6 +195,9 @@ enum netc_stg_stage {
/* Port MAC 0/1 Receive Ethernet Octets Counter */
#define NETC_PM_REOCT(a) (0x1100 + (a) * 0x400)
+/* Port MAC 0/1 Receive Octets Counter */
+#define NETC_PM_ROCT(a) (0x1108 + (a) * 0x400)
+
/* Port MAC 0/1 Receive Alignment Error Counter Register */
#define NETC_PM_RALN(a) (0x1110 + (a) * 0x400)
@@ -188,12 +210,27 @@ enum netc_stg_stage {
/* Port MAC 0/1 Receive Frame Check Sequence Error Counter */
#define NETC_PM_RFCS(a) (0x1128 + (a) * 0x400)
+/* Port MAC 0/1 Receive VLAN Frame Counter */
+#define NETC_PM_RVLAN(a) (0x1130 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Frame Error Counter */
+#define NETC_PM_RERR(a) (0x1138 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Unicast Frame Counter */
+#define NETC_PM_RUCA(a) (0x1140 + (a) * 0x400)
+
/* Port MAC 0/1 Receive Multicast Frame Counter */
#define NETC_PM_RMCA(a) (0x1148 + (a) * 0x400)
/* Port MAC 0/1 Receive Broadcast Frame Counter */
#define NETC_PM_RBCA(a) (0x1150 + (a) * 0x400)
+/* Port MAC 0/1 Receive Dropped Packets Counter */
+#define NETC_PM_RDRP(a) (0x1158 + (a) * 0x400)
+
+/* Port MAC 0/1 Receive Packets Counter */
+#define NETC_PM_RPKT(a) (0x1160 + (a) * 0x400)
+
/* Port MAC 0/1 Receive Undersized Packet Counter */
#define NETC_PM_RUND(a) (0x1168 + (a) * 0x400)
@@ -236,6 +273,9 @@ enum netc_stg_stage {
/* Port MAC 0/1 Transmit Ethernet Octets Counter */
#define NETC_PM_TEOCT(a) (0x1200 + (a) * 0x400)
+/* Port MAC 0/1 Transmit Octets Counter */
+#define NETC_PM_TOCT(a) (0x1208 + (a) * 0x400)
+
/* Port MAC 0/1 Transmit Excessive Deferral Packet Counter */
#define NETC_PM_TEDFR(a) (0x1210 + (a) * 0x400)
@@ -245,15 +285,30 @@ enum netc_stg_stage {
/* Port MAC 0/1 Transmit Frame Counter */
#define NETC_PM_TFRM(a) (0x1220 + (a) * 0x400)
+/* Port MAC 0/1 Transmit Frame Check Sequence Error Counter */
+#define NETC_PM_TFCS(a) (0x1228 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit VLAN Frame Counter */
+#define NETC_PM_TVLAN(a) (0x1230 + (a) * 0x400)
+
/* Port MAC 0/1 Transmit Frame Error Counter */
#define NETC_PM_TERR(a) (0x1238 + (a) * 0x400)
+/* Port MAC 0/1 Transmit Unicast Frame Counter */
+#define NETC_PM_TUCA(a) (0x1240 + (a) * 0x400)
+
/* Port MAC 0/1 Transmit Multicast Frame Counter */
#define NETC_PM_TMCA(a) (0x1248 + (a) * 0x400)
/* Port MAC 0/1 Transmit Broadcast Frame Counter */
#define NETC_PM_TBCA(a) (0x1250 + (a) * 0x400)
+/* Port MAC 0/1 Transmit Packets Counter */
+#define NETC_PM_TPKT(a) (0x1260 + (a) * 0x400)
+
+/* Port MAC 0/1 Transmit Undersized Packet Counter */
+#define NETC_PM_TUND(a) (0x1268 + (a) * 0x400)
+
/* Port MAC 0/1 Transmit 64-Octet Packet Counter */
#define NETC_PM_T64(a) (0x1270 + (a) * 0x400)
@@ -293,6 +348,9 @@ enum netc_stg_stage {
/* Port MAC 0/1 Transmit Excessive Collisions Counter */
#define NETC_PM_TECOL(a) (0x12f0 + (a) * 0x400)
+/* Port MAC 0/1 Transmit Invalid Octets Counter */
+#define NETC_PM_TIOCT(a) (0x12f8 + (a) * 0x400)
+
#define NETC_PEMDIOCR 0x1c00
#define NETC_EMDIO_BASE NETC_PEMDIOCR
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] nfc: nci: Add skb length validation in nci_core_init_rsp_packet
From: kernel test robot @ 2026-04-30 3:03 UTC (permalink / raw)
To: Dudu Lu, netdev
Cc: llvm, oe-kbuild-all, davem, edumazet, kuba, pabeni, Dudu Lu
In-Reply-To: <20260413090102.77980-1-phx0fer@gmail.com>
Hi Dudu,
kernel test robot noticed the following build errors:
[auto build test ERROR on net/main]
[also build test ERROR on net-next/main linus/master horms-ipvs/master v7.1-rc1 next-20260429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Dudu-Lu/nfc-nci-Add-skb-length-validation-in-nci_core_init_rsp_packet/20260423-210923
base: net/main
patch link: https://lore.kernel.org/r/20260413090102.77980-1-phx0fer%40gmail.com
patch subject: [PATCH] nfc: nci: Add skb length validation in nci_core_init_rsp_packet
config: arm64-randconfig-004-20260430 (https://download.01.org/0day-ci/archive/20260430/202604301024.q9hVP893-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 5bac06718f502014fade905512f1d26d578a18f3)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260430/202604301024.q9hVP893-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604301024.q9hVP893-lkp@intel.com/
All errors (new ones prefixed by >>):
>> net/nfc/nci/rsp.c:1:2: error: expected identifier or '('
1 | if (skb->len < sizeof(*rsp)) {
| ^
net/nfc/nci/rsp.c:5:2: error: expected identifier or '('
5 | if (skb->len < 6 + rsp_1->num_supported_rf_interfaces +
| ^
net/nfc/nci/rsp.c:10:2: error: expected identifier or '('
10 | if (skb->len < sizeof(*rsp_1))
| ^
In file included from net/nfc/nci/rsp.c:29:
In file included from include/linux/interrupt.h:11:
In file included from include/linux/hardirq.h:11:
In file included from arch/arm64/include/asm/hardirq.h:17:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:588:
In file included from include/linux/irqdesc.h:5:
In file included from include/linux/irq_work.h:6:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:98:11: warning: array index 3 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
98 | return (set->sig[3] | set->sig[2] |
| ^ ~
include/uapi/asm-generic/signal.h:62:2: note: array 'sig' declared here
62 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from net/nfc/nci/rsp.c:29:
In file included from include/linux/interrupt.h:11:
In file included from include/linux/hardirq.h:11:
In file included from arch/arm64/include/asm/hardirq.h:17:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:588:
In file included from include/linux/irqdesc.h:5:
In file included from include/linux/irq_work.h:6:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:98:25: warning: array index 2 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
98 | return (set->sig[3] | set->sig[2] |
| ^ ~
include/uapi/asm-generic/signal.h:62:2: note: array 'sig' declared here
62 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from net/nfc/nci/rsp.c:29:
In file included from include/linux/interrupt.h:11:
In file included from include/linux/hardirq.h:11:
In file included from arch/arm64/include/asm/hardirq.h:17:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:588:
In file included from include/linux/irqdesc.h:5:
In file included from include/linux/irq_work.h:6:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:99:4: warning: array index 1 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
99 | set->sig[1] | set->sig[0]) == 0;
| ^ ~
include/uapi/asm-generic/signal.h:62:2: note: array 'sig' declared here
62 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from net/nfc/nci/rsp.c:29:
In file included from include/linux/interrupt.h:11:
In file included from include/linux/hardirq.h:11:
In file included from arch/arm64/include/asm/hardirq.h:17:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:588:
In file included from include/linux/irqdesc.h:5:
In file included from include/linux/irq_work.h:6:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:101:11: warning: array index 1 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
101 | return (set->sig[1] | set->sig[0]) == 0;
| ^ ~
include/uapi/asm-generic/signal.h:62:2: note: array 'sig' declared here
62 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from net/nfc/nci/rsp.c:29:
In file included from include/linux/interrupt.h:11:
In file included from include/linux/hardirq.h:11:
In file included from arch/arm64/include/asm/hardirq.h:17:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:588:
In file included from include/linux/irqdesc.h:5:
In file included from include/linux/irq_work.h:6:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:114:11: warning: array index 3 is past the end of the array (that has type 'const unsigned long[1]') [-Warray-bounds]
114 | return (set1->sig[3] == set2->sig[3]) &&
| ^ ~
include/uapi/asm-generic/signal.h:62:2: note: array 'sig' declared here
62 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from net/nfc/nci/rsp.c:29:
In file included from include/linux/interrupt.h:11:
In file included from include/linux/hardirq.h:11:
In file included from arch/arm64/include/asm/hardirq.h:17:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:588:
In file included from include/linux/irqdesc.h:5:
In file included from include/linux/irq_work.h:6:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:114:27: warning: array index 3 is past the end of the array (that has type 'const unsigned long[1]') [-Warray-bounds]
114 | return (set1->sig[3] == set2->sig[3]) &&
vim +1 net/nfc/nci/rsp.c
> 1 if (skb->len < sizeof(*rsp)) {
2 pr_err("short NCI_CORE_INIT_RSP v2 packet\n");
3 return NCI_STATUS_SYNTAX_ERROR;
4 }
5 if (skb->len < 6 + rsp_1->num_supported_rf_interfaces +
6 sizeof(*rsp_2)) {
7 pr_err("short NCI_CORE_INIT_RSP v1 packet\n");
8 return NCI_STATUS_SYNTAX_ERROR;
9 }
10 if (skb->len < sizeof(*rsp_1))
11 return NCI_STATUS_SYNTAX_ERROR;
12 // SPDX-License-Identifier: GPL-2.0-only
13 /*
14 * The NFC Controller Interface is the communication protocol between an
15 * NFC Controller (NFCC) and a Device Host (DH).
16 *
17 * Copyright (C) 2011 Texas Instruments, Inc.
18 *
19 * Written by Ilan Elias <ilane@ti.com>
20 *
21 * Acknowledgements:
22 * This file is based on hci_event.c, which was written
23 * by Maxim Krasnyansky.
24 */
25
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH net v2 15/15] drivers: net: 8390: wd80x3: Remove this driver
From: kernel test robot @ 2026-04-30 3:14 UTC (permalink / raw)
To: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan
Cc: oe-kbuild-all, netdev, Geert Uytterhoeven, Michael Fritscher,
Byron Stanoszek, Daniel Palmer, linux-kernel, linux-doc
In-Reply-To: <20260422-v7-0-0-net-next-driver-removal-v1-v2-15-08a5b59784d5@lunn.ch>
Hi Andrew,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 1f5ffc672165ff851063a5fd044b727ab2517ae3]
url: https://github.com/intel-lab-lkp/linux/commits/Andrew-Lunn/drivers-net-3com-3c509-Remove-this-driver/20260424-104110
base: 1f5ffc672165ff851063a5fd044b727ab2517ae3
patch link: https://lore.kernel.org/r/20260422-v7-0-0-net-next-driver-removal-v1-v2-15-08a5b59784d5%40lunn.ch
patch subject: [PATCH net v2 15/15] drivers: net: 8390: wd80x3: Remove this driver
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260430/202604300512.3KcfhJGd-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604300512.3KcfhJGd-lkp@intel.com/
All warnings (new ones prefixed by >>):
Non-Preserved Properties
======================== [docutils]
>> Documentation/networking/device_drivers/ethernet/index.rst:10: WARNING: toctree contains reference to nonexisting document 'networking/device_drivers/ethernet/3com/3c509' [toc.not_readable]
Documentation/networking/skbuff:36: ./include/linux/skbuff.h:48: ERROR: Unexpected section title.
vim +10 Documentation/networking/device_drivers/ethernet/index.rst
132db93572821e Jakub Kicinski 2020-06-26 7
132db93572821e Jakub Kicinski 2020-06-26 8 Contents:
132db93572821e Jakub Kicinski 2020-06-26 9
132db93572821e Jakub Kicinski 2020-06-26 @10 .. toctree::
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* RE: [RFC Patch net-next v2 4/8] r8169: add support for new interrupt mapping
From: Javen @ 2026-04-30 3:24 UTC (permalink / raw)
To: Vadim Fedorenko, hkallweit1@gmail.com, nic_swsd@realtek.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, horms@kernel.org
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <40fadbd2-e138-4000-85b2-dd4188d43e19@linux.dev>
>On 29/04/2026 08:07, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> To support RSS, the number of hardware interrupt bits should match the
>> interrupt of software. So we add support for new interrupt mapping here.
>> ISR_VER_MAP_REG is the hardware register to indicate interrupt status.
>> IMR_SET_VEC_MAP_REG is interrupt mask which is set to enable irq.
>>
>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>
>[...]
>
>>
>> napi = &tp->r8169napi[i];
>> snprintf(irq->name, len, "%s-%d", dev->name, i); @@
>> -5664,10 +5717,17 @@ static const struct net_device_ops rtl_netdev_ops
>> = {
>>
>> static void rtl_set_irq_mask(struct rtl8169_private *tp)
>> {
>> - tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
>> + if (tp->features & RTL_VEC_MAP_ENABLE) {
>> + tp->irq_mask = ISRIMR_LINKCHG;
>> + tp->irq_mask |= ISRIMR_TOK_Q0;
>
> nit: you can set it in one line
>
>> + for (int i = 0; i < tp->num_rx_rings; i++)
>> + tp->irq_mask |= ISRIMR_ROK_Q0 << i;
>> + } else {
>> + tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
>>
>> - if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
>> - tp->irq_mask |= SYSErr | RxFIFOOver;
>> + if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
>> + tp->irq_mask |= SYSErr | RxFIFOOver;
>> + }
>> }
>>
>> static int rtl_alloc_irq(struct rtl8169_private *tp) @@ -5695,6
>> +5755,16 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
>> if (nvecs < 0)
>> nvecs = pci_alloc_irq_vectors(pdev, 1, 1,
>> PCI_IRQ_ALL_TYPES);
>>
>> + tp->features &= ~RTL_VEC_MAP_ENABLE;
>> +
>> + if (nvecs > 0) {
>> + tp->irq_nvecs = nvecs;
>> + tp->irq = pci_irq_vector(pdev, 0);
>> + if (nvecs > 1)
>> + tp->features |= RTL_VEC_MAP_ENABLE;
>> + return 0;
>> + }
>> +
>> tp->irq = pdev->irq;
>> tp->irq_nvecs = 1;
>
>now these 2 lines are not needed, because in success they are never executed,
>but in error path they provide wrong information.
>
>the whole can be rewritten with error path in case both tries of
>pci_alloc_irq_vectors failed and the common code for success path:
>
> if (nvecs < 0)
> nvecs = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
>
> if (nvecs < 0)
> return nvecs;
>
> tp->irq_nvecs = nvecs;
> tp->irq = pci_irq_vector(pdev, 0);
>
> if (nvecs > 1)
> tp->features |= RTL_VEC_MAP_ENABLE;
>
> return 0;
>
>>
>> @@ -5965,6 +6035,53 @@ static bool rtl_aspm_is_safe(struct
>rtl8169_private *tp)
>> return false;
>> }
>>
>> +static int rtl8169_poll_msix_rx(struct napi_struct *napi, int budget)
>> +{
>> + struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi,
>napi);
>> + struct rtl8169_private *tp = r8169_napi->priv;
>> + struct net_device *dev = tp->dev;
>> + const int message_id = r8169_napi->index;
>
>reverse xmass tree, please
>
>> + int work_done = 0;
>> +
>> + if (message_id < tp->num_rx_rings)
>> + work_done += rtl_rx(dev, tp, &tp->rx_ring[message_id],
>> + budget);
>> +
>> + if (work_done < budget && napi_complete_done(napi, work_done))
>> + rtl8169_enable_hw_interrupt_msix(tp, message_id);
>> +
>> + return work_done;
>> +}
>> +
>> +static int rtl8169_poll_msix_tx(struct napi_struct *napi, int budget)
>> +{
>> + struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi,
>napi);
>> + struct rtl8169_private *tp = r8169_napi->priv;
>> + struct net_device *dev = tp->dev;
>> + unsigned int work_done = 0;
>> + const int message_id = r8169_napi->index;
>> + int tx_ring_idx = message_id - 8;
>
>ditto
>
>> +
>> + if (tx_ring_idx >= 0)
>> + rtl_tx(dev, tp, budget);
>> +
>> + if (work_done < budget && napi_complete_done(napi, work_done))
>> + rtl8169_enable_hw_interrupt_msix(tp, message_id);
>> +
>> + return work_done;
>> +}
>> +
>> +static int rtl8169_poll_msix_other(struct napi_struct *napi, int
>> +budget) {
>> + struct rtl8169_napi *r8169_napi = container_of(napi, struct rtl8169_napi,
>napi);
>> + struct rtl8169_private *tp = r8169_napi->priv;
>> + const int message_id = r8169_napi->index;
>> +
>> + napi_complete_done(napi, budget);
>> + rtl8169_enable_hw_interrupt_msix(tp, message_id);
>> +
>> + return 1;
>> +}
>> +
>> static void r8169_init_napi(struct rtl8169_private *tp)
>> {
>> for (int i = 0; i < tp->irq_nvecs; i++) { @@ -5972,6 +6089,20 @@
>> static void r8169_init_napi(struct rtl8169_private *tp)
>> int (*poll)(struct napi_struct *napi, int budget);
>>
>> poll = rtl8169_poll;
>> + if (tp->features & RTL_VEC_MAP_ENABLE) {
>> + switch (tp->hw_curr_isr_ver) {
>> + case 6:
>> + if (i < R8127_MAX_RX_QUEUES)
>> + poll = rtl8169_poll_msix_rx;
>> + else if (i > 7 && i < 16)
>
> magic constants?
>
>> + poll = rtl8169_poll_msix_tx;
>> + else
>> + poll = rtl8169_poll_msix_other;
>> + break;
>> + default:
>> + break;
>> + }
>> + }
>> netif_napi_add(tp->dev, &r8169napi->napi, poll);
>> r8169napi->priv = tp;
>> r8169napi->index = i;
Thanks for your review. I have applied all the comments locally. Once the ongoing discussion concludes, I will send the next version.
BRs,
Javen
^ permalink raw reply
* [PATCH v2 net-next 2/8] selftests/ptp: Extract print_system_timestamp helper in testptp
From: Arthur Kiyanovski @ 2026-04-30 3:24 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
Extract the repeated switch-on-clockid pattern used for printing
system timestamps into a reusable helper function. This removes
code duplication in the -x (PTP_SYS_OFFSET_EXTENDED) output path
and prepares for additional callers.
No functional change.
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
tools/testing/selftests/ptp/testptp.c | 70 ++++++++++++---------------
1 file changed, 32 insertions(+), 38 deletions(-)
diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c
index ed1e288..d3bcfd0 100644
--- a/tools/testing/selftests/ptp/testptp.c
+++ b/tools/testing/selftests/ptp/testptp.c
@@ -153,6 +153,28 @@ static void usage(char *progname)
progname, PTP_MAX_SAMPLES);
}
+static void print_system_timestamp(int sample_num, __kernel_clockid_t clockid,
+ long long sec, unsigned int nsec,
+ const char *when)
+{
+ switch (clockid) {
+ case CLOCK_REALTIME:
+ printf("sample #%2d: real time %s: %lld.%09u\n",
+ sample_num, when, sec, nsec);
+ break;
+ case CLOCK_MONOTONIC:
+ printf("sample #%2d: monotonic time %s: %lld.%09u\n",
+ sample_num, when, sec, nsec);
+ break;
+ case CLOCK_MONOTONIC_RAW:
+ printf("sample #%2d: monotonic-raw time %s: %lld.%09u\n",
+ sample_num, when, sec, nsec);
+ break;
+ default:
+ break;
+ }
+}
+
int main(int argc, char *argv[])
{
struct ptp_clock_caps caps;
@@ -608,46 +630,18 @@ int main(int argc, char *argv[])
getextended);
for (i = 0; i < getextended; i++) {
- switch (ext_clockid) {
- case CLOCK_REALTIME:
- printf("sample #%2d: real time before: %lld.%09u\n",
- i, soe->ts[i][0].sec,
- soe->ts[i][0].nsec);
- break;
- case CLOCK_MONOTONIC:
- printf("sample #%2d: monotonic time before: %lld.%09u\n",
- i, soe->ts[i][0].sec,
- soe->ts[i][0].nsec);
- break;
- case CLOCK_MONOTONIC_RAW:
- printf("sample #%2d: monotonic-raw time before: %lld.%09u\n",
- i, soe->ts[i][0].sec,
- soe->ts[i][0].nsec);
- break;
- default:
- break;
- }
+ print_system_timestamp(i, ext_clockid,
+ soe->ts[i][0].sec,
+ soe->ts[i][0].nsec,
+ "before");
+
printf(" phc time: %lld.%09u\n",
soe->ts[i][1].sec, soe->ts[i][1].nsec);
- switch (ext_clockid) {
- case CLOCK_REALTIME:
- printf(" real time after: %lld.%09u\n",
- soe->ts[i][2].sec,
- soe->ts[i][2].nsec);
- break;
- case CLOCK_MONOTONIC:
- printf(" monotonic time after: %lld.%09u\n",
- soe->ts[i][2].sec,
- soe->ts[i][2].nsec);
- break;
- case CLOCK_MONOTONIC_RAW:
- printf(" monotonic-raw time after: %lld.%09u\n",
- soe->ts[i][2].sec,
- soe->ts[i][2].nsec);
- break;
- default:
- break;
- }
+
+ print_system_timestamp(i, ext_clockid,
+ soe->ts[i][2].sec,
+ soe->ts[i][2].nsec,
+ "after");
}
}
--
2.47.3
^ permalink raw reply related
* [PATCH v2 net-next 3/8] selftests/ptp: Add testptp support for attributes ioctls
From: Arthur Kiyanovski @ 2026-04-30 3:25 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
Add support for testing the new PTP_SYS_OFFSET_EXTENDED_ATTRS and
PTP_SYS_OFFSET_PRECISE_ATTRS ioctls in the testptp utility.
New command-line options:
-a: Get extended offset with attributes (error_bound, clock_status,
timescale)
-A: Get precise cross-timestamp with attributes
These options allow testing and validation of PHC devices that provide
clock quality information alongside timestamps.
Also display the new clock_attrs capability in the -c output, and
update print_system_timestamp to print unrecognized clock types instead
of silently dropping them.
Signed-off-by: Amit Bernstein <amitbern@amazon.com>
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
tools/testing/selftests/ptp/testptp.c | 105 +++++++++++++++++++++++++-
1 file changed, 103 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c
index d3bcfd0..99eb346 100644
--- a/tools/testing/selftests/ptp/testptp.c
+++ b/tools/testing/selftests/ptp/testptp.c
@@ -147,10 +147,13 @@ static void usage(char *progname)
" -t val shift the ptp clock time by 'val' seconds\n"
" -T val set the ptp clock time to 'val' seconds\n"
" -x val get an extended ptp clock time with the desired number of samples (up to %d)\n"
+ " -a val get extended timestamps with attributes (error_bound,\n"
+ " clock_status, timescale, counter), up to %d samples\n"
" -X get a ptp clock cross timestamp\n"
+ " -A get a precise cross timestamp with attributes\n"
" -y val pre/post tstamp timebase to use {realtime|monotonic|monotonic-raw}\n"
" -z test combinations of rising/falling external time stamp flags\n",
- progname, PTP_MAX_SAMPLES);
+ progname, PTP_MAX_SAMPLES, PTP_MAX_SAMPLES);
}
static void print_system_timestamp(int sample_num, __kernel_clockid_t clockid,
@@ -171,6 +174,8 @@ static void print_system_timestamp(int sample_num, __kernel_clockid_t clockid,
sample_num, when, sec, nsec);
break;
default:
+ printf("sample #%2d: unknown clock %d %s: %lld.%09u\n",
+ sample_num, clockid, when, sec, nsec);
break;
}
}
@@ -188,6 +193,8 @@ int main(int argc, char *argv[])
struct ptp_sys_offset *sysoff;
struct ptp_sys_offset_extended *soe;
struct ptp_sys_offset_precise *xts;
+ struct ptp_sys_offset_precise_attrs *xtsa;
+ struct ptp_sys_offset_extended_attrs *soea;
char *progname;
unsigned int i;
@@ -208,7 +215,9 @@ int main(int argc, char *argv[])
int list_pins = 0;
int pct_offset = 0;
int getextended = 0;
+ int getextendedattrs = 0;
int getcross = 0;
+ int getcrossattrs = 0;
int n_samples = 0;
int pin_index = -1, pin_func;
int pps = -1;
@@ -226,7 +235,7 @@ int main(int argc, char *argv[])
progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
- while (EOF != (c = getopt(argc, argv, "cd:e:E:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xy:z"))) {
+ while (EOF != (c = getopt(argc, argv, "a:Acd:e:E:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xy:z"))) {
switch (c) {
case 'c':
capabilities = 1;
@@ -311,9 +320,22 @@ int main(int argc, char *argv[])
return -1;
}
break;
+ case 'a':
+ getextendedattrs = atoi(optarg);
+ if (getextendedattrs < 1 ||
+ getextendedattrs > PTP_MAX_SAMPLES) {
+ fprintf(stderr,
+ "number of extended attrs timestamp samples must be between 1 and %d; was asked for %d\n",
+ PTP_MAX_SAMPLES, getextendedattrs);
+ return -1;
+ }
+ break;
case 'X':
getcross = 1;
break;
+ case 'A':
+ getcrossattrs = 1;
+ break;
case 'y':
if (!strcasecmp(optarg, "realtime"))
ext_clockid = CLOCK_REALTIME;
@@ -367,6 +389,7 @@ int main(int argc, char *argv[])
" %d programmable pins\n"
" %d cross timestamping\n"
" %d adjust_phase\n"
+ " %d clock_attrs\n"
" %d maximum phase adjustment (ns)\n",
caps.max_adj,
caps.n_alarm,
@@ -376,6 +399,7 @@ int main(int argc, char *argv[])
caps.n_pins,
caps.cross_timestamping,
caps.adjust_phase,
+ caps.clock_attrs,
caps.max_phase_adj);
}
}
@@ -648,6 +672,50 @@ int main(int argc, char *argv[])
free(soe);
}
+ if (getextendedattrs) {
+ soea = calloc(1, sizeof(*soea));
+ if (!soea) {
+ perror("calloc");
+ return -1;
+ }
+
+ soea->n_samples = getextendedattrs;
+ soea->clockid = ext_clockid;
+
+ if (ioctl(fd, PTP_SYS_OFFSET_EXTENDED_ATTRS, soea)) {
+ perror("PTP_SYS_OFFSET_EXTENDED_ATTRS");
+ } else {
+ printf("extended timestamp request returned %d samples\n",
+ getextendedattrs);
+
+ for (i = 0; i < getextendedattrs; i++) {
+ print_system_timestamp(i, ext_clockid,
+ soea->ts[i][0].pct.sec,
+ soea->ts[i][0].pct.nsec,
+ "before");
+
+ printf(" phc time: %lld.%09u, error bound: %u, clock status: %u, timescale: %u\n",
+ soea->ts[i][1].pct.sec,
+ soea->ts[i][1].pct.nsec,
+ soea->ts[i][1].att.error_bound,
+ soea->ts[i][1].att.status,
+ soea->ts[i][1].att.timescale);
+
+ if (soea->ts[i][1].att.counter_id)
+ printf(" counter: %llu (id: %u)\n",
+ (unsigned long long)soea->ts[i][1].att.counter_value,
+ soea->ts[i][1].att.counter_id);
+
+ print_system_timestamp(i, ext_clockid,
+ soea->ts[i][2].pct.sec,
+ soea->ts[i][2].pct.nsec,
+ "after");
+ }
+ }
+
+ free(soea);
+ }
+
if (getcross) {
xts = calloc(1, sizeof(*xts));
if (!xts) {
@@ -671,6 +739,39 @@ int main(int argc, char *argv[])
free(xts);
}
+ if (getcrossattrs) {
+ xtsa = calloc(1, sizeof(*xtsa));
+ if (!xtsa) {
+ perror("calloc");
+ return -1;
+ }
+
+ if (ioctl(fd, PTP_SYS_OFFSET_PRECISE_ATTRS, xtsa)) {
+ perror("PTP_SYS_OFFSET_PRECISE_ATTRS");
+ } else {
+ puts("system and phc crosstimestamping with attributes request okay");
+
+ printf("device time: %lld.%09u\n",
+ xtsa->device.pct.sec, xtsa->device.pct.nsec);
+ printf("error_bound: %u ns\n",
+ xtsa->device.att.error_bound);
+ printf("status: %u\n",
+ xtsa->device.att.status);
+ printf("timescale: %u\n",
+ xtsa->device.att.timescale);
+ if (xtsa->device.att.counter_id)
+ printf("counter: %llu (id: %u)\n",
+ (unsigned long long)xtsa->device.att.counter_value,
+ xtsa->device.att.counter_id);
+ printf("system time: %lld.%09u\n",
+ xtsa->sys_realtime.sec, xtsa->sys_realtime.nsec);
+ printf("monoraw time: %lld.%09u\n",
+ xtsa->sys_monoraw.sec, xtsa->sys_monoraw.nsec);
+ }
+
+ free(xtsa);
+ }
+
if (channel >= 0) {
if (ioctl(fd, PTP_MASK_CLEAR_ALL)) {
perror("PTP_MASK_CLEAR_ALL");
--
2.47.3
^ permalink raw reply related
* [PATCH v2 net-next 1/8] ptp: Add ioctls for PHC timestamps with quality attributes
From: Arthur Kiyanovski @ 2026-04-30 3:24 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
Introduce two new ioctls that extend existing PTP timestamp interfaces
with clock quality information:
- PTP_SYS_OFFSET_EXTENDED_ATTRS: Extends PTP_SYS_OFFSET_EXTENDED
- PTP_SYS_OFFSET_PRECISE_ATTRS: Extends PTP_SYS_OFFSET_PRECISE
These ioctls provide quality attributes alongside timestamps:
1. error_bound: Maximum deviation from true time (nanoseconds), based
on device's internal clock state
2. clock_status: Synchronization state (unknown, initializing,
synchronized, free-running, unreliable)
3. timescale: Time reference (TAI, UTC, etc.)
4. counter_value: Raw hardware counter (e.g. TSC ticks) at the time of
the PHC reading, for feed-forward calibration use cases
5. counter_id: Identifies the hardware counter type (enum ptp_counter_id)
This supports three use cases:
1. Managed PHC devices (e.g., ENA, vmclock) that maintain their own
synchronization and can report quality metrics directly to userspace
without requiring ptp4l
2. Applications that need complete time quality information in a single
call, regardless of how the PHC is synchronized
3. VMMs that need raw hardware counter values paired
with PTP timestamps for feed-forward clock calibration, avoiding the
feedback loop inherent in NTP-style synchronization
Timescale definitions use a Continuity/Discipline framework to describe
timeline properties and steering behavior consistently across all
entries.
This implementation is based on the RFC discussion linked below.
Link: https://lore.kernel.org/netdev/20250724115657.150-1-darinzon@amazon.com/
Signed-off-by: Amit Bernstein <amitbern@amazon.com>
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
drivers/ptp/ptp_chardev.c | 137 +++++++++++++++++--
drivers/ptp/ptp_clock.c | 4 +-
include/linux/ptp_clock_kernel.h | 30 +++++
include/uapi/linux/ptp_clock.h | 225 ++++++++++++++++++++++++++++++-
4 files changed, 381 insertions(+), 15 deletions(-)
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index c61cf9e..1377c6a 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -190,6 +190,8 @@ static long ptp_clock_getcaps(struct ptp_clock *ptp, void __user *arg)
.cross_timestamping = ptp->info->getcrosststamp != NULL,
.adjust_phase = ptp->info->adjphase != NULL &&
ptp->info->getmaxphase != NULL,
+ .clock_attrs = ptp->info->gettimexattrs64 ||
+ ptp->info->getcrosststampattrs,
};
if (caps.adjust_phase)
@@ -343,15 +345,69 @@ static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg,
return copy_to_user(arg, &precise_offset, sizeof(precise_offset)) ? -EFAULT : 0;
}
+static long ptp_sys_offset_precise_attrs(struct ptp_clock *ptp, void __user *arg)
+{
+ struct ptp_sys_offset_precise_attrs precise_offset_attrs;
+ struct system_device_crosststamp xtstamp;
+ struct ptp_clock_attributes att;
+ struct timespec64 ts;
+ int err;
+
+ if (!ptp->info->getcrosststampattrs)
+ return -EOPNOTSUPP;
+
+ err = ptp->info->getcrosststampattrs(ptp->info, &xtstamp, &att);
+ if (err)
+ return err;
+
+ memset(&precise_offset_attrs, 0, sizeof(precise_offset_attrs));
+ ts = ktime_to_timespec64(xtstamp.device);
+ precise_offset_attrs.device.pct.sec = ts.tv_sec;
+ precise_offset_attrs.device.pct.nsec = ts.tv_nsec;
+ precise_offset_attrs.device.att.error_bound = att.error_bound;
+ precise_offset_attrs.device.att.timescale = att.timescale;
+ precise_offset_attrs.device.att.status = att.status;
+ precise_offset_attrs.device.att.counter_id = att.counter_id;
+ precise_offset_attrs.device.att.counter_value = att.counter_value;
+
+ ts = ktime_to_timespec64(xtstamp.sys_realtime);
+ precise_offset_attrs.sys_realtime.sec = ts.tv_sec;
+ precise_offset_attrs.sys_realtime.nsec = ts.tv_nsec;
+
+ ts = ktime_to_timespec64(xtstamp.sys_monoraw);
+ precise_offset_attrs.sys_monoraw.sec = ts.tv_sec;
+ precise_offset_attrs.sys_monoraw.nsec = ts.tv_nsec;
+
+ return copy_to_user(arg, &precise_offset_attrs,
+ sizeof(precise_offset_attrs)) ? -EFAULT : 0;
+}
+
typedef int (*ptp_gettimex_fn)(struct ptp_clock_info *,
struct timespec64 *,
struct ptp_system_timestamp *);
+static int ptp_validate_sys_offset_clockid(__kernel_clockid_t clockid)
+{
+ switch (clockid) {
+ case CLOCK_REALTIME:
+ case CLOCK_MONOTONIC:
+ case CLOCK_MONOTONIC_RAW:
+ return 0;
+ case CLOCK_AUX ... CLOCK_AUX_LAST:
+ if (IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
+ return 0;
+ fallthrough;
+ default:
+ return -EINVAL;
+ }
+}
+
static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg,
ptp_gettimex_fn gettimex_fn)
{
struct ptp_sys_offset_extended *extoff __free(kfree) = NULL;
struct ptp_system_timestamp sts;
+ int err;
if (!gettimex_fn)
return -EOPNOTSUPP;
@@ -363,23 +419,13 @@ static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg,
if (extoff->n_samples > PTP_MAX_SAMPLES || extoff->rsv[0] || extoff->rsv[1])
return -EINVAL;
- switch (extoff->clockid) {
- case CLOCK_REALTIME:
- case CLOCK_MONOTONIC:
- case CLOCK_MONOTONIC_RAW:
- break;
- case CLOCK_AUX ... CLOCK_AUX_LAST:
- if (IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
- break;
- fallthrough;
- default:
- return -EINVAL;
- }
+ err = ptp_validate_sys_offset_clockid(extoff->clockid);
+ if (err)
+ return err;
sts.clockid = extoff->clockid;
for (unsigned int i = 0; i < extoff->n_samples; i++) {
struct timespec64 ts;
- int err;
err = gettimex_fn(ptp->info, &ts, &sts);
if (err)
@@ -400,6 +446,65 @@ static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg,
return copy_to_user(arg, extoff, sizeof(*extoff)) ? -EFAULT : 0;
}
+static long ptp_sys_offset_extended_attrs(struct ptp_clock *ptp, void __user *arg)
+{
+ struct ptp_sys_offset_extended_attrs *extoffattrs __free(kfree) = NULL;
+ struct ptp_system_timestamp sts;
+ struct ptp_clock_attributes att;
+ int err;
+
+ if (!ptp->info->gettimexattrs64)
+ return -EOPNOTSUPP;
+
+ extoffattrs = memdup_user(arg, sizeof(*extoffattrs));
+ if (IS_ERR(extoffattrs))
+ return PTR_ERR(extoffattrs);
+
+ if (extoffattrs->n_samples > PTP_MAX_SAMPLES ||
+ extoffattrs->rsv[0] ||
+ extoffattrs->rsv[1])
+ return -EINVAL;
+
+ err = ptp_validate_sys_offset_clockid(extoffattrs->clockid);
+ if (err)
+ return err;
+
+ sts.clockid = extoffattrs->clockid;
+ for (unsigned int i = 0; i < extoffattrs->n_samples; i++) {
+ struct timespec64 ts;
+
+ err = ptp->info->gettimexattrs64(ptp->info, &ts, &sts, &att);
+ if (err)
+ return err;
+
+ /* Filter out disabled or unavailable clocks */
+ if (sts.pre_ts.tv_sec < 0 || sts.post_ts.tv_sec < 0)
+ return -EINVAL;
+
+ /* System timestamps have no clock attributes.
+ * Zero them to avoid confusion.
+ */
+ memset(&extoffattrs->ts[i][0].att, 0,
+ sizeof(extoffattrs->ts[i][0].att));
+ memset(&extoffattrs->ts[i][2].att, 0,
+ sizeof(extoffattrs->ts[i][2].att));
+
+ extoffattrs->ts[i][0].pct.sec = sts.pre_ts.tv_sec;
+ extoffattrs->ts[i][0].pct.nsec = sts.pre_ts.tv_nsec;
+ extoffattrs->ts[i][1].pct.sec = ts.tv_sec;
+ extoffattrs->ts[i][1].pct.nsec = ts.tv_nsec;
+ extoffattrs->ts[i][1].att.error_bound = att.error_bound;
+ extoffattrs->ts[i][1].att.timescale = att.timescale;
+ extoffattrs->ts[i][1].att.status = att.status;
+ extoffattrs->ts[i][1].att.counter_id = att.counter_id;
+ extoffattrs->ts[i][1].att.counter_value = att.counter_value;
+ extoffattrs->ts[i][2].pct.sec = sts.post_ts.tv_sec;
+ extoffattrs->ts[i][2].pct.nsec = sts.post_ts.tv_nsec;
+ }
+
+ return copy_to_user(arg, extoffattrs, sizeof(*extoffattrs)) ? -EFAULT : 0;
+}
+
static long ptp_sys_offset(struct ptp_clock *ptp, void __user *arg)
{
struct ptp_sys_offset *sysoff __free(kfree) = NULL;
@@ -535,11 +640,17 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
return ptp_sys_offset_precise(ptp, argptr,
ptp->info->getcrosststamp);
+ case PTP_SYS_OFFSET_PRECISE_ATTRS:
+ return ptp_sys_offset_precise_attrs(ptp, argptr);
+
case PTP_SYS_OFFSET_EXTENDED:
case PTP_SYS_OFFSET_EXTENDED2:
return ptp_sys_offset_extended(ptp, argptr,
ptp->info->gettimex64);
+ case PTP_SYS_OFFSET_EXTENDED_ATTRS:
+ return ptp_sys_offset_extended_attrs(ptp, argptr);
+
case PTP_SYS_OFFSET:
case PTP_SYS_OFFSET2:
return ptp_sys_offset(ptp, argptr);
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index d6f54cc..849aef8 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -112,7 +112,9 @@ static int ptp_clock_gettime(struct posix_clock *pc, struct timespec64 *tp)
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
int err;
- if (ptp->info->gettimex64)
+ if (ptp->info->gettimexattrs64)
+ err = ptp->info->gettimexattrs64(ptp->info, tp, NULL, NULL);
+ else if (ptp->info->gettimex64)
err = ptp->info->gettimex64(ptp->info, tp, NULL);
else
err = ptp->info->gettime64(ptp->info, tp);
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
index 8843645..489e21b 100644
--- a/include/linux/ptp_clock_kernel.h
+++ b/include/linux/ptp_clock_kernel.h
@@ -122,11 +122,34 @@ struct ptp_system_timestamp {
* reading the lowest bits of the PHC timestamp and the second
* reading immediately follows that.
*
+ * @gettimexattrs64: Reads the current time from the hardware clock and
+ * optionally also the system clock with additional clock
+ * attributes.
+ * parameter ts: Holds the PHC timestamp.
+ * parameter sts: If not NULL, it holds a pair of
+ * timestamps from the system clock. The first reading is
+ * made right before reading the lowest bits of the PHC
+ * timestamp and the second reading immediately follows that.
+ * parameter att: If not NULL, it holds the maximum error
+ * bound for the returned PHC timestamp in nanoseconds,
+ * the timescale for the returned PHC timestamp and the
+ * clock's qualitative synchronization status.
+ *
* @getcrosststamp: Reads the current time from the hardware clock and
* system clock simultaneously.
* parameter cts: Contains timestamp (device,system) pair,
* where system time is realtime and monotonic.
*
+ * @getcrosststampattrs: Reads the current time from the hardware clock and
+ * system clock simultaneously with additional data on
+ * hardware clock accuracy and reliability.
+ * parameter cts: Contains timestamp (device,system)
+ * pair, where system time is realtime and monotonic.
+ * parameter att: If not NULL, it holds the maximum error
+ * bound for the returned PHC timestamp in nanoseconds,
+ * the timescale for the returned PHC timestamp and the
+ * clock's qualitative synchronization status.
+ *
* @settime64: Set the current time on the hardware clock.
* parameter ts: Time value to set.
*
@@ -208,8 +231,15 @@ struct ptp_clock_info {
int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
int (*gettimex64)(struct ptp_clock_info *ptp, struct timespec64 *ts,
struct ptp_system_timestamp *sts);
+ int (*gettimexattrs64)(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts,
+ struct ptp_clock_attributes *att);
int (*getcrosststamp)(struct ptp_clock_info *ptp,
struct system_device_crosststamp *cts);
+ int (*getcrosststampattrs)(struct ptp_clock_info *ptp,
+ struct system_device_crosststamp *cts,
+ struct ptp_clock_attributes *att);
int (*settime64)(struct ptp_clock_info *p, const struct timespec64 *ts);
int (*getcycles64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
int (*getcyclesx64)(struct ptp_clock_info *ptp, struct timespec64 *ts,
diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h
index 46d45f9..83dc668 100644
--- a/include/uapi/linux/ptp_clock.h
+++ b/include/uapi/linux/ptp_clock.h
@@ -79,6 +79,137 @@
*/
#define PTP_PEROUT_V1_VALID_FLAGS (0)
+/*
+ * Clock status values for struct ptp_clock_attributes.status
+ */
+enum ptp_clock_status {
+ /* Clock synchronization status cannot be reliably determined */
+ PTP_CLOCK_STATUS_UNKNOWN = 0,
+
+ /* Clock is acquiring synchronization */
+ PTP_CLOCK_STATUS_INITIALIZING = 1,
+
+ /* Clock is synchronized and maintained accurately by the device */
+ PTP_CLOCK_STATUS_SYNCED = 2,
+
+ /* Clock is drifting but remains within acceptable error bounds */
+ PTP_CLOCK_STATUS_HOLDOVER = 3,
+
+ /* Clock is drifting without adjustments or synchronization */
+ PTP_CLOCK_STATUS_FREE_RUNNING = 4,
+
+ /* Clock is unreliable, the error_bound value cannot be trusted */
+ PTP_CLOCK_STATUS_UNRELIABLE = 5
+};
+
+/*
+ * Clock timescale values for struct ptp_clock_attributes.timescale.
+ *
+ * These definitions describe the mathematical properties and reference
+ * epochs of the timescale provided by the PHC.
+ *
+ * Discipline: Describes the frequency/phase steering behavior.
+ * Continuity: Describes whether the timeline is uninterrupted.
+ */
+enum ptp_clock_timescale {
+ /* Unknown or unspecified timescale */
+ PTP_TIMESCALE_UNKNOWN = 0,
+
+ /********************* Absolute Atomic Timescales *********************
+ * These timescales are continuous, monotonic standards based on atomic
+ * physics. They do not experience phase jumps.
+ **********************************************************************/
+
+ /**
+ * International Atomic Time (TAI)
+ * Epoch: 1958-01-01 00:00:00.
+ * Continuity: Strictly monotonic and continuous; no leap seconds.
+ * Discipline: Primary atomic reference; no phase jumps.
+ */
+ PTP_TIMESCALE_TAI = 1,
+
+ /**
+ * Terrestrial Time (TT)
+ * Epoch: 1958-01-01 00:00:00.
+ * Continuity: Strictly monotonic and continuous; no leap seconds.
+ * Discipline: Defined as TAI + 32.184s constant offset.
+ */
+ PTP_TIMESCALE_TT = 2,
+
+ /**
+ * Global Positioning System (GPS) Time
+ * Epoch: 1980-01-06 00:00:00.
+ * Continuity: Strictly monotonic and continuous; no leap seconds.
+ * Discipline: Defined by the GPS constellation; fixed offset from TAI.
+ */
+ PTP_TIMESCALE_GPS = 3,
+
+ /****************** UTC-Based Timescales (Civil Time) *****************
+ * These timescales are derived from TAI but adjusted to align with
+ * the Earth's rotation, primarily through leap seconds.
+ **********************************************************************/
+
+ /**
+ * Coordinated Universal Time (UTC) - Wall-clock (CLOCK_REALTIME)
+ * Epoch: 1970-01-01 00:00:00 (Unix epoch).
+ * Continuity: Discontinuous; subject to 1-second leap second
+ * phase jumps.
+ * Discipline: Frequency steered; incorporates leap second corrections.
+ *
+ * Note: Leap-smeared UTC MUST NOT be advertised as PTP_TIMESCALE_UTC.
+ * Smear algorithms are not standardized and the resulting timescale
+ * is ambiguous. Implementations using smeared UTC MUST advertise
+ * PTP_TIMESCALE_UNKNOWN or PTP_TIMESCALE_PROPRIETARY instead.
+ */
+ PTP_TIMESCALE_UTC = 4,
+
+ /**
+ * POSIX Time (Unix Time)
+ * Epoch: 1970-01-01 00:00:00.
+ * Continuity: Discontinuous; leap seconds handled by
+ * repeating/skipping values.
+ * Discipline: Follows UTC frequency steering and phase jumps.
+ */
+ PTP_TIMESCALE_POSIX = 5,
+
+ /****************** System-Relative Monotonic Clocks ******************
+ * These timescales are relative to a system event (like boot)
+ * and are not synchronized to an external atomic standard.
+ **********************************************************************/
+
+ /**
+ * Monotonic System Clock (CLOCK_MONOTONIC)
+ * Epoch: Arbitrary (System boot time).
+ * Continuity: Strictly monotonic; no leap seconds.
+ * Discipline: Frequency steered to match system reference;
+ * does not advance during suspend.
+ */
+ PTP_TIMESCALE_MONOTONIC = 6,
+
+ /**
+ * Raw Monotonic System Clock (CLOCK_MONOTONIC_RAW)
+ * Epoch: Arbitrary (System boot time).
+ * Continuity: Strictly monotonic; no leap seconds.
+ * Discipline: Raw hardware oscillator; no frequency steering
+ * or discipline.
+ */
+ PTP_TIMESCALE_MONOTONIC_RAW = 7,
+
+ /**
+ * Boot Time System Clock (CLOCK_BOOTTIME)
+ * Epoch: Arbitrary (System boot time).
+ * Continuity: Strictly monotonic and continuous; no leap seconds.
+ * Discipline: Frequency steered to match system reference;
+ * advances during suspend.
+ */
+ PTP_TIMESCALE_BOOTTIME = 8,
+
+ /********************** Vendor-Specific Timescale *********************/
+
+ /* A proprietary or vendor-specific timescale with custom rules. */
+ PTP_TIMESCALE_PROPRIETARY = 9,
+};
+
/*
* struct ptp_clock_time - represents a time value
*
@@ -94,6 +225,61 @@ struct ptp_clock_time {
__u32 reserved;
};
+/*
+ * Hardware counter identifiers for struct ptp_clock_attributes.counter_id
+ */
+enum ptp_counter_id {
+ /* Counter value not available or type not specified */
+ PTP_COUNTER_UNKNOWN = 0,
+
+ /* x86 Time Stamp Counter (TSC) */
+ PTP_COUNTER_X86_TSC = 1,
+
+ /* ARM Generic Timer virtual counter */
+ PTP_COUNTER_ARM_ARCH = 2,
+};
+
+/*
+ * struct ptp_clock_attributes - describes additional data for a PTP clock
+ * timestamp
+ *
+ * @error_bound: The maximum possible error (in nanoseconds) associated with
+ * the reported timestamp, this value quantifies the inaccuracy
+ * of the clock at the time of reading. A value of UINT_MAX
+ * indicates that the error bound is unknown or unavailable.
+ * @timescale: Clock timescale for timestamp interpretation
+ * (enum ptp_clock_timescale).
+ * @status: Qualitative synchronization status of the clock
+ * (enum ptp_clock_status).
+ * @counter_id: Identifies the hardware counter used to produce
+ * counter_value (enum ptp_counter_id).
+ * PTP_COUNTER_UNKNOWN (0) means no counter is available.
+ * @rsv: Reserved for future use, should be set to zero.
+ * @counter_value: Raw hardware counter value (e.g. TSC ticks) captured at
+ * the time of the PHC timestamp reading. Zero with
+ * counter_id == PTP_COUNTER_UNKNOWN means not available.
+ */
+struct ptp_clock_attributes {
+ __u32 error_bound;
+ __u8 timescale;
+ __u8 status;
+ __u8 counter_id;
+ __u8 rsv;
+ __u64 counter_value;
+};
+
+/*
+ * struct ptp_clock_time_attributes - PTP timestamp with its associated
+ * attributes
+ *
+ * @pct: PTP clock timestamp value.
+ * @att: PTP clock timestamp attributes.
+ */
+struct ptp_clock_time_attributes {
+ struct ptp_clock_time pct;
+ struct ptp_clock_attributes att;
+};
+
struct ptp_clock_caps {
int max_adj; /* Maximum frequency adjustment in parts per billon. */
int n_alarm; /* Number of programmable alarms. */
@@ -106,7 +292,9 @@ struct ptp_clock_caps {
/* Whether the clock supports adjust phase */
int adjust_phase;
int max_phase_adj; /* Maximum phase adjustment in nanoseconds. */
- int rsv[11]; /* Reserved for future use. */
+ /* Whether the clock supports attrs ioctls */
+ int clock_attrs;
+ int rsv[10]; /* Reserved for future use. */
};
struct ptp_extts_request {
@@ -180,6 +368,30 @@ struct ptp_sys_offset_extended {
struct ptp_clock_time ts[PTP_MAX_SAMPLES][3];
};
+/*
+ * ptp_sys_offset_extended_attrs - data structure for IOCTL operation
+ * PTP_SYS_OFFSET_EXTENDED_ATTRS
+ *
+ * @n_samples: Desired number of measurements.
+ * @clockid: clockid of a clock-base used for pre/post timestamps.
+ * @rsv: Reserved for future use.
+ * @ts: Array of samples in the form [pre-TS, PHC, post-TS].
+ * Each sample consists of timestamp in the form [sec, nsec],
+ * while the PHC sample also includes clock attributes in the form
+ * [error_bound, timescale, status].
+ *
+ * Starting from kernel 6.12 and onwards, the first word of the reserved-field
+ * is used for @clockid. That's backward compatible since previous kernel
+ * expect all three reserved words (@rsv[3]) to be 0 while the clockid (first
+ * word in the new structure) for CLOCK_REALTIME is '0'.
+ */
+struct ptp_sys_offset_extended_attrs {
+ unsigned int n_samples;
+ __kernel_clockid_t clockid;
+ unsigned int rsv[2];
+ struct ptp_clock_time_attributes ts[PTP_MAX_SAMPLES][3];
+};
+
struct ptp_sys_offset_precise {
struct ptp_clock_time device;
struct ptp_clock_time sys_realtime;
@@ -187,6 +399,13 @@ struct ptp_sys_offset_precise {
unsigned int rsv[4]; /* Reserved for future use. */
};
+struct ptp_sys_offset_precise_attrs {
+ struct ptp_clock_time_attributes device;
+ struct ptp_clock_time sys_realtime;
+ struct ptp_clock_time sys_monoraw;
+ unsigned int rsv[2]; /* Reserved for future use. */
+};
+
enum ptp_pin_function {
PTP_PF_NONE,
PTP_PF_EXTTS,
@@ -252,6 +471,10 @@ struct ptp_pin_desc {
_IOWR(PTP_CLK_MAGIC, 21, struct ptp_sys_offset_precise)
#define PTP_SYS_OFFSET_EXTENDED_CYCLES \
_IOWR(PTP_CLK_MAGIC, 22, struct ptp_sys_offset_extended)
+#define PTP_SYS_OFFSET_PRECISE_ATTRS \
+ _IOWR(PTP_CLK_MAGIC, 23, struct ptp_sys_offset_precise_attrs)
+#define PTP_SYS_OFFSET_EXTENDED_ATTRS \
+ _IOWR(PTP_CLK_MAGIC, 24, struct ptp_sys_offset_extended_attrs)
struct ptp_extts_event {
struct ptp_clock_time t; /* Time event occurred. */
--
2.47.3
^ permalink raw reply related
* [PATCH v2 net-next 0/8] ptp: Add PHC timestamp quality attributes
From: Arthur Kiyanovski @ 2026-04-30 3:24 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
This series adds quality attributes to PTP Hardware Clock (PHC)
timestamps, allowing userspace to obtain error bound, clock status,
timescale, and raw counter values alongside timestamps in a single
call.
Motivation
----------
The existing PTP APIs return timestamps without any indication of
their quality. Applications that need clock accuracy and
synchronization status commonly rely on external tools such as
ptp4l, which implement synchronization logic and can export their
measurement of clock accuracy. For managed PHC devices — such as
the ENA network adapter, whose clock is synchronized by the device
without userspace involvement — these tools are not available, and
the existing APIs lack a way to report quality metrics to consumers
of time.
This was previously proposed as an RFC [1] with a single ioctl.
Based on community feedback, the design was reworked to cover both
the extended (multi-sample) and precise (cross-timestamp) paths,
with a shared attributes structure.
Design
------
This series introduces two new ioctls that extend the existing
extended and precise timestamp paths with per-timestamp quality
attributes: error bound (nanoseconds), clock synchronization
status, timescale, and raw hardware counter values.
A capability flag is added to ptp_clock_caps so userspace can
discover attributes support.
Patches 2-3 add testptp support for the new ioctls.
Patch 4 implements the attributes for ptp_vmclock, reporting
error bound, clock status, timescale, and raw counter values.
Patches 5-8 implement the attributes for the ENA driver,
reporting error bound from the device's PHC layer.
v2:
- Fix build bisectability: move ena_com.c consumer updates into
patch 6/8 and ena_phc.c caller update into patch 7/8 so each
patch compiles independently.
- Add missing Cc for Amit Bernstein (co-author of ENA patches).
[1] https://lore.kernel.org/netdev/20250724115657.150-1-darinzon@amazon.com/
Arthur Kiyanovski (8):
ptp: Add ioctls for PHC timestamps with quality attributes
selftests/ptp: Extract print_system_timestamp helper in testptp
selftests/ptp: Add testptp support for attributes ioctls
ptp: ptp_vmclock: Implement attributes ioctls
net: ena: PHC: Check return code before setting timestamp output
net: ena: Update PHC admin interface for error bound support
net: ena: Add error bound to PHC communication layer
net: ena: Implement gettimexattrs64 callback for PTP attributes
.../device_drivers/ethernet/amazon/ena.rst | 2 +
.../net/ethernet/amazon/ena/ena_admin_defs.h | 17 +-
drivers/net/ethernet/amazon/ena/ena_com.c | 47 ++--
drivers/net/ethernet/amazon/ena/ena_com.h | 5 +-
drivers/net/ethernet/amazon/ena/ena_debugfs.c | 3 +
drivers/net/ethernet/amazon/ena/ena_phc.c | 67 +++++-
drivers/ptp/ptp_chardev.c | 137 ++++++++++-
drivers/ptp/ptp_clock.c | 4 +-
drivers/ptp/ptp_vmclock.c | 195 +++++++++++++--
include/linux/ptp_clock_kernel.h | 30 +++
include/uapi/linux/ptp_clock.h | 225 +++++++++++++++++-
tools/testing/selftests/ptp/testptp.c | 175 ++++++++++----
12 files changed, 799 insertions(+), 108 deletions(-)
--
2.47.3
^ permalink raw reply
* [PATCH v2 net-next 4/8] ptp: ptp_vmclock: Implement attributes ioctls
From: Arthur Kiyanovski @ 2026-04-30 3:25 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
Implement the gettimexattrs64 and getcrosststampattrs callbacks in the
ptp_vmclock driver to provide clock quality attributes through the new
PTP_SYS_OFFSET_EXTENDED_ATTRS and PTP_SYS_OFFSET_PRECISE_ATTRS ioctls.
The ptp_vmclock device exposes:
- error_bound: Derived from time_maxerror_nanosec, accumulated with
counter frequency error (counter_period_maxerror_rate_frac_sec) over
elapsed counter ticks
- clock_status: Mapped from the device's clock_status field
- timescale: Determined from time_type (UTC, TAI, monotonic, etc.)
The legacy ioctls return -EINVAL when clock_status is UNRELIABLE since
they have no way to communicate clock state to userspace. The attrs
ioctls have a status field for this purpose, so they treat UNRELIABLE
as success and let userspace check the status field.
To avoid a race where the hypervisor could update clock_status between
the timestamp call and the UNRELIABLE check, the clock state is captured
inside the seq_count loop for a consistent snapshot with the timestamp.
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
drivers/ptp/ptp_vmclock.c | 195 ++++++++++++++++++++++++++++++++++----
1 file changed, 179 insertions(+), 16 deletions(-)
diff --git a/drivers/ptp/ptp_vmclock.c b/drivers/ptp/ptp_vmclock.c
index 8b630eb..5657c06 100644
--- a/drivers/ptp/ptp_vmclock.c
+++ b/drivers/ptp/ptp_vmclock.c
@@ -53,6 +53,17 @@ struct vmclock_state {
char *name;
};
+/**
+ * struct vmclock_crosststamp_ctx - context for get_device_system_crosststamp()
+ * @st: vmclock device state
+ * @attrs: optional output for PTP clock attributes, populated inside the
+ * seq_count loop for a consistent snapshot with the timestamp
+ */
+struct vmclock_crosststamp_ctx {
+ struct vmclock_state *st;
+ struct ptp_clock_attributes *attrs;
+};
+
#define VMCLOCK_MAX_WAIT ms_to_ktime(100)
/* Require at least the flags field to be present. All else can be optional. */
@@ -95,14 +106,109 @@ static bool tai_adjust(struct vmclock_abi *clk, uint64_t *sec)
return false;
}
+static uint8_t vmclock_get_ptp_timescale(uint8_t vmclock_time_type)
+{
+ switch (vmclock_time_type) {
+ case VMCLOCK_TIME_UTC:
+ return PTP_TIMESCALE_UTC;
+ case VMCLOCK_TIME_TAI:
+ return PTP_TIMESCALE_TAI;
+ case VMCLOCK_TIME_MONOTONIC:
+ return PTP_TIMESCALE_MONOTONIC;
+ default:
+ return PTP_TIMESCALE_UNKNOWN;
+ }
+}
+
+static uint8_t vmclock_get_ptp_status(uint8_t vmclock_status)
+{
+ switch (vmclock_status) {
+ case VMCLOCK_STATUS_UNKNOWN:
+ return PTP_CLOCK_STATUS_UNKNOWN;
+ case VMCLOCK_STATUS_INITIALIZING:
+ return PTP_CLOCK_STATUS_INITIALIZING;
+ case VMCLOCK_STATUS_SYNCHRONIZED:
+ return PTP_CLOCK_STATUS_SYNCED;
+ case VMCLOCK_STATUS_FREERUNNING:
+ return PTP_CLOCK_STATUS_FREE_RUNNING;
+ case VMCLOCK_STATUS_UNRELIABLE:
+ return PTP_CLOCK_STATUS_UNRELIABLE;
+ default:
+ return PTP_CLOCK_STATUS_UNKNOWN;
+ }
+}
+
+static void vmclock_populate_ptp_attributes(struct vmclock_state *st,
+ struct ptp_clock_attributes *att,
+ uint64_t delta,
+ uint64_t cycle)
+{
+ uint64_t maxerror_ns = UINT_MAX;
+
+ if (!att)
+ return;
+
+ /* Only calculate if the base error is flagged as valid
+ * by the hypervisor.
+ */
+ if (VMCLOCK_FIELD_PRESENT(st->clk, time_maxerror_nanosec) &&
+ (le64_to_cpu(st->clk->flags) & VMCLOCK_FLAG_TIME_MAXERROR_VALID)) {
+ maxerror_ns = le64_to_cpu(st->clk->time_maxerror_nanosec);
+
+ /* If frequency error is also valid, accumulate it
+ * over the delta.
+ */
+ if (VMCLOCK_FIELD_PRESENT(st->clk, counter_period_maxerror_rate_frac_sec) &&
+ (le64_to_cpu(st->clk->flags) & VMCLOCK_FLAG_PERIOD_MAXERROR_VALID)) {
+ uint64_t maxerror_rate, err_hi, err_frac, growth_ns;
+
+ maxerror_rate = le64_to_cpu(st->clk->counter_period_maxerror_rate_frac_sec);
+ err_frac = mul_u64_u64_shr_add_u64(&err_hi, delta,
+ maxerror_rate,
+ st->clk->counter_period_shift,
+ 0);
+
+ growth_ns = (err_hi * NSEC_PER_SEC) +
+ mul_u64_u64_shr(err_frac, NSEC_PER_SEC, 64);
+
+ /* Guard against overflow */
+ if (U64_MAX - growth_ns < maxerror_ns)
+ maxerror_ns = U64_MAX;
+ else
+ maxerror_ns += growth_ns;
+ }
+ }
+
+ /* PTP UAPI error_bound is 32-bit nanoseconds */
+ att->error_bound = (maxerror_ns > UINT_MAX) ?
+ UINT_MAX : (uint32_t)maxerror_ns;
+ att->timescale = vmclock_get_ptp_timescale(st->clk->time_type);
+ att->status = vmclock_get_ptp_status(st->clk->clock_status);
+
+ att->counter_value = cycle;
+ switch (st->cs_id) {
+ case CSID_X86_TSC:
+ att->counter_id = PTP_COUNTER_X86_TSC;
+ break;
+ case CSID_ARM_ARCH_COUNTER:
+ att->counter_id = PTP_COUNTER_ARM_ARCH;
+ break;
+ default:
+ att->counter_id = PTP_COUNTER_UNKNOWN;
+ break;
+ }
+}
+
static int vmclock_get_crosststamp(struct vmclock_state *st,
struct ptp_system_timestamp *sts,
struct system_counterval_t *system_counter,
- struct timespec64 *tspec)
+ struct timespec64 *tspec,
+ struct ptp_clock_attributes *attrs)
{
ktime_t deadline = ktime_add(ktime_get(), VMCLOCK_MAX_WAIT);
struct system_time_snapshot systime_snapshot;
uint64_t cycle, delta, seq, frac_sec;
+ uint8_t clock_status = VMCLOCK_STATUS_UNKNOWN;
#ifdef CONFIG_X86
/*
@@ -122,9 +228,6 @@ static int vmclock_get_crosststamp(struct vmclock_state *st,
*/
virt_rmb();
- if (st->clk->clock_status == VMCLOCK_STATUS_UNRELIABLE)
- return -EINVAL;
-
/*
* When invoked for gettimex64(), fill in the pre/post system
* times. The simple case is when system time is based on the
@@ -163,6 +266,18 @@ static int vmclock_get_crosststamp(struct vmclock_state *st,
if (!tai_adjust(st->clk, &tspec->tv_sec))
return -EINVAL;
+ /*
+ * Capture clock state inside the seq_count loop for a
+ * consistent snapshot with the timestamp. The attrs path
+ * reports it to userspace via the status field; the legacy
+ * path saves it for the UNRELIABLE check after the loop.
+ */
+ if (attrs)
+ vmclock_populate_ptp_attributes(st, attrs, delta,
+ cycle);
+ else
+ clock_status = st->clk->clock_status;
+
/*
* This pairs with a write barrier in the hypervisor
* which populates this structure.
@@ -186,6 +301,17 @@ static int vmclock_get_crosststamp(struct vmclock_state *st,
sts->post_ts = sts->pre_ts;
}
+ /*
+ * If attrs is set, attributes were already populated inside the
+ * seq_count loop. Return success even for UNRELIABLE — the attrs
+ * ioctl can report the status to userspace.
+ */
+ if (attrs)
+ return 0;
+
+ if (clock_status == VMCLOCK_STATUS_UNRELIABLE)
+ return -EINVAL;
+
return 0;
}
@@ -198,7 +324,8 @@ static int vmclock_get_crosststamp(struct vmclock_state *st,
static int vmclock_get_crosststamp_kvmclock(struct vmclock_state *st,
struct ptp_system_timestamp *sts,
struct system_counterval_t *system_counter,
- struct timespec64 *tspec)
+ struct timespec64 *tspec,
+ struct ptp_clock_attributes *attrs)
{
struct pvclock_vcpu_time_info *pvti = this_cpu_pvti();
unsigned int pvti_ver;
@@ -209,7 +336,8 @@ static int vmclock_get_crosststamp_kvmclock(struct vmclock_state *st,
do {
pvti_ver = pvclock_read_begin(pvti);
- ret = vmclock_get_crosststamp(st, sts, system_counter, tspec);
+ ret = vmclock_get_crosststamp(st, sts, system_counter, tspec,
+ attrs);
if (ret)
break;
@@ -238,17 +366,19 @@ static int ptp_vmclock_get_time_fn(ktime_t *device_time,
struct system_counterval_t *system_counter,
void *ctx)
{
- struct vmclock_state *st = ctx;
+ struct vmclock_crosststamp_ctx *vctx = ctx;
+ struct vmclock_state *st = vctx->st;
struct timespec64 tspec;
int ret;
#ifdef SUPPORT_KVMCLOCK
if (READ_ONCE(st->sys_cs_id) == CSID_X86_KVM_CLK)
ret = vmclock_get_crosststamp_kvmclock(st, NULL, system_counter,
- &tspec);
+ &tspec, vctx->attrs);
else
#endif
- ret = vmclock_get_crosststamp(st, NULL, system_counter, &tspec);
+ ret = vmclock_get_crosststamp(st, NULL, system_counter, &tspec,
+ vctx->attrs);
if (!ret)
*device_time = timespec64_to_ktime(tspec);
@@ -256,12 +386,11 @@ static int ptp_vmclock_get_time_fn(ktime_t *device_time,
return ret;
}
-static int ptp_vmclock_getcrosststamp(struct ptp_clock_info *ptp,
- struct system_device_crosststamp *xtstamp)
+static int ptp_vmclock_do_getcrosststamp(struct vmclock_crosststamp_ctx *vctx,
+ struct system_device_crosststamp *xtstamp)
{
- struct vmclock_state *st = container_of(ptp, struct vmclock_state,
- ptp_clock_info);
- int ret = get_device_system_crosststamp(ptp_vmclock_get_time_fn, st,
+ struct vmclock_state *st = vctx->st;
+ int ret = get_device_system_crosststamp(ptp_vmclock_get_time_fn, vctx,
NULL, xtstamp);
#ifdef SUPPORT_KVMCLOCK
/*
@@ -278,13 +407,23 @@ static int ptp_vmclock_getcrosststamp(struct ptp_clock_info *ptp,
systime_snapshot.cs_id == CSID_X86_KVM_CLK) {
WRITE_ONCE(st->sys_cs_id, systime_snapshot.cs_id);
ret = get_device_system_crosststamp(ptp_vmclock_get_time_fn,
- st, NULL, xtstamp);
+ vctx, NULL, xtstamp);
}
}
#endif
return ret;
}
+static int ptp_vmclock_getcrosststamp(struct ptp_clock_info *ptp,
+ struct system_device_crosststamp *xtstamp)
+{
+ struct vmclock_state *st = container_of(ptp, struct vmclock_state,
+ ptp_clock_info);
+ struct vmclock_crosststamp_ctx vctx = { .st = st };
+
+ return ptp_vmclock_do_getcrosststamp(&vctx, xtstamp);
+}
+
/*
* PTP clock operations
*/
@@ -311,7 +450,29 @@ static int ptp_vmclock_gettimex(struct ptp_clock_info *ptp, struct timespec64 *t
struct vmclock_state *st = container_of(ptp, struct vmclock_state,
ptp_clock_info);
- return vmclock_get_crosststamp(st, sts, NULL, ts);
+ return vmclock_get_crosststamp(st, sts, NULL, ts, NULL);
+}
+
+static int ptp_vmclock_gettimexattrs(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts,
+ struct ptp_clock_attributes *att)
+{
+ struct vmclock_state *st = container_of(ptp, struct vmclock_state,
+ ptp_clock_info);
+
+ return vmclock_get_crosststamp(st, sts, NULL, ts, att);
+}
+
+static int ptp_vmclock_getcrosststampattrs(struct ptp_clock_info *ptp,
+ struct system_device_crosststamp *xtstamp,
+ struct ptp_clock_attributes *att)
+{
+ struct vmclock_state *st = container_of(ptp, struct vmclock_state,
+ ptp_clock_info);
+ struct vmclock_crosststamp_ctx vctx = { .st = st, .attrs = att };
+
+ return ptp_vmclock_do_getcrosststamp(&vctx, xtstamp);
}
static int ptp_vmclock_enable(struct ptp_clock_info *ptp,
@@ -329,9 +490,11 @@ static const struct ptp_clock_info ptp_vmclock_info = {
.adjfine = ptp_vmclock_adjfine,
.adjtime = ptp_vmclock_adjtime,
.gettimex64 = ptp_vmclock_gettimex,
+ .gettimexattrs64 = ptp_vmclock_gettimexattrs,
.settime64 = ptp_vmclock_settime,
.enable = ptp_vmclock_enable,
.getcrosststamp = ptp_vmclock_getcrosststamp,
+ .getcrosststampattrs = ptp_vmclock_getcrosststampattrs,
};
static struct ptp_clock *vmclock_ptp_register(struct device *dev,
--
2.47.3
^ permalink raw reply related
* [PATCH v2 net-next 5/8] net: ena: PHC: Check return code before setting timestamp output
From: Arthur Kiyanovski @ 2026-04-30 3:25 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
ena_phc_gettimex64() is setting the output parameter regardless
of whether ena_com_phc_get_timestamp() succeeded or failed.
When ena_com_phc_get_timestamp() returns an error, the timestamp
parameter may contain uninitialized stack memory (e.g., when PHC is
disabled or in blocked state) or invalid hardware values. Passing
these to userspace via the PTP ioctl is both a security issue
(information leak) and a correctness bug.
Fix by checking the return code after releasing the lock and only
setting the output timestamp on success.
Fixes: e0ea34158ee8 ("net: ena: Add PHC support in the ENA driver")
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
drivers/net/ethernet/amazon/ena/ena_phc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amazon/ena/ena_phc.c b/drivers/net/ethernet/amazon/ena/ena_phc.c
index 7867e89..c2a3ff1 100644
--- a/drivers/net/ethernet/amazon/ena/ena_phc.c
+++ b/drivers/net/ethernet/amazon/ena/ena_phc.c
@@ -46,9 +46,12 @@ static int ena_phc_gettimex64(struct ptp_clock_info *clock_info,
spin_unlock_irqrestore(&phc_info->lock, flags);
+ if (rc)
+ return rc;
+
*ts = ns_to_timespec64(timestamp_nsec);
- return rc;
+ return 0;
}
static int ena_phc_settime64(struct ptp_clock_info *clock_info,
--
2.47.3
^ permalink raw reply related
* [PATCH v2 net-next 6/8] net: ena: Update PHC admin interface for error bound support
From: Arthur Kiyanovski @ 2026-04-30 3:25 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
Extend the ENA admin interface to support error bound.
Add error_bound to the PHC response structure.
Introduce a feature version mechanism to indicate device supports
error_bound, and add an error flag for error_bound retrieval failures.
This enables the driver to retrieve error_bound information from the
device alongside timestamps.
Signed-off-by: Amit Bernstein <amitbern@amazon.com>
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
.../net/ethernet/amazon/ena/ena_admin_defs.h | 17 +++++++++++------
drivers/net/ethernet/amazon/ena/ena_com.c | 11 ++++++-----
2 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
index 898ecd9..2d132c4 100644
--- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
@@ -128,12 +128,14 @@ enum ena_admin_get_stats_scope {
ENA_ADMIN_ETH_TRAFFIC = 1,
};
-enum ena_admin_phc_type {
- ENA_ADMIN_PHC_TYPE_READLESS = 0,
+enum ena_admin_phc_feature_version {
+ /* Readless with error_bound */
+ ENA_ADMIN_PHC_FEATURE_VERSION_0 = 0,
};
enum ena_admin_phc_error_flags {
ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP = BIT(0),
+ ENA_ADMIN_PHC_ERROR_FLAG_ERROR_BOUND = BIT(1),
};
/* ENA SRD configuration for ENI */
@@ -1035,10 +1037,10 @@ struct ena_admin_queue_ext_feature_desc {
};
struct ena_admin_feature_phc_desc {
- /* PHC type as defined in enum ena_admin_get_phc_type,
- * used only for GET command.
+ /* PHC version as defined in enum ena_admin_phc_feature_version,
+ * used only for GET command as max supported PHC version by the device.
*/
- u8 type;
+ u8 version;
/* Reserved - MBZ */
u8 reserved1[3];
@@ -1224,7 +1226,10 @@ struct ena_admin_phc_resp {
/* PHC timestamp (nsec) */
u64 timestamp;
- u8 reserved2[12];
+ u8 reserved2[8];
+
+ /* Timestamp error limit (nsec) */
+ u32 error_bound;
/* Bit field of enum ena_admin_phc_error_flags */
u32 error_flags;
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index e67b592..1549d6e 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -1682,11 +1682,11 @@ int ena_com_phc_config(struct ena_com_dev *ena_dev)
struct ena_admin_set_feat_cmd set_feat_cmd;
int ret = 0;
- /* Get device PHC default configuration */
+ /* Get default device PHC configuration */
ret = ena_com_get_feature(ena_dev,
&get_feat_resp,
ENA_ADMIN_PHC_CONFIG,
- 0);
+ ENA_ADMIN_PHC_FEATURE_VERSION_0);
if (unlikely(ret)) {
netdev_err(ena_dev->net_device,
"Failed to get PHC feature configuration, error: %d\n",
@@ -1694,10 +1694,11 @@ int ena_com_phc_config(struct ena_com_dev *ena_dev)
return ret;
}
- /* Supporting only readless PHC retrieval */
- if (get_feat_resp.u.phc.type != ENA_ADMIN_PHC_TYPE_READLESS) {
+ /* Supporting only PHC V0 (readless mode with error bound) */
+ if (get_feat_resp.u.phc.version != ENA_ADMIN_PHC_FEATURE_VERSION_0) {
netdev_err(ena_dev->net_device,
- "Unsupported PHC type, error: %d\n",
+ "Unsupported PHC version (0x%X), error: %d\n",
+ get_feat_resp.u.phc.version,
-EOPNOTSUPP);
return -EOPNOTSUPP;
}
--
2.47.3
^ permalink raw reply related
* [PATCH v2 net-next 7/8] net: ena: Add error bound to PHC communication layer
From: Arthur Kiyanovski @ 2026-04-30 3:25 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
Extend the ENA PHC communication layer to retrieve error bound from
the device.
Update ena_com_phc_get_timestamp() to retrieve error_bound alongside
timestamps.
Add error handling and statistics for error_bound retrieval failures.
Signed-off-by: Amit Bernstein <amitbern@amazon.com>
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
.../device_drivers/ethernet/amazon/ena.rst | 2 ++
drivers/net/ethernet/amazon/ena/ena_com.c | 36 ++++++++++++-------
drivers/net/ethernet/amazon/ena/ena_com.h | 5 ++-
drivers/net/ethernet/amazon/ena/ena_debugfs.c | 3 ++
drivers/net/ethernet/amazon/ena/ena_phc.c | 3 +-
5 files changed, 34 insertions(+), 15 deletions(-)
diff --git a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst
index 14784a0..ce9ba84 100644
--- a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst
+++ b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst
@@ -306,6 +306,8 @@ PHC errors must remain below 1% of all PHC requests to maintain the desired leve
**phc_err_dv** | Number of failed get time attempts due to device errors (entering into block state).
**phc_err_ts** | Number of failed get time attempts due to timestamp errors (entering into block state),
| This occurs if driver exceeded the request limit or device received an invalid timestamp.
+**phc_err_eb** | Number of failed get time attempts due to error bound errors (entering into block state),
+ | This occurs if device received an excessively high or invalid error bound.
================= ======================================================
PHC timeouts:
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index 1549d6e..981e8e4 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -45,7 +45,8 @@
#define ENA_PHC_DEFAULT_EXPIRE_TIMEOUT_USEC 10
#define ENA_PHC_DEFAULT_BLOCK_TIMEOUT_USEC 1000
#define ENA_PHC_REQ_ID_OFFSET 0xDEAD
-#define ENA_PHC_ERROR_FLAGS (ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP)
+#define ENA_PHC_ERROR_FLAGS (ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP | \
+ ENA_ADMIN_PHC_ERROR_FLAG_ERROR_BOUND)
/*****************************************************************************/
/*****************************************************************************/
@@ -1726,7 +1727,7 @@ int ena_com_phc_config(struct ena_com_dev *ena_dev)
if (phc->expire_timeout_usec > phc->block_timeout_usec)
phc->expire_timeout_usec = phc->block_timeout_usec;
- /* Prepare PHC feature command */
+ /* Prepare PHC config feature command */
memset(&set_feat_cmd, 0x0, sizeof(set_feat_cmd));
set_feat_cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
set_feat_cmd.feat_common.feature_id = ENA_ADMIN_PHC_CONFIG;
@@ -1781,7 +1782,8 @@ void ena_com_phc_destroy(struct ena_com_dev *ena_dev)
phc->virt_addr = NULL;
}
-int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
+int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp,
+ u32 *error_bound)
{
volatile struct ena_admin_phc_resp *resp = ena_dev->phc.virt_addr;
const ktime_t zero_system_time = ktime_set(0, 0);
@@ -1825,6 +1827,8 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
* a PHC error, this occurs if device:
* - exceeded the get time request limit
* - received an invalid timestamp
+ * - received an excessively high error bound
+ * - received an invalid error bound
*/
netdev_err(ena_dev->net_device,
"PHC get time request 0x%x failed (error 0x%x)\n",
@@ -1832,9 +1836,11 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
resp->error_flags);
phc->stats.phc_err_ts += !!(resp->error_flags &
ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP);
+ phc->stats.phc_err_eb += !!(resp->error_flags &
+ ENA_ADMIN_PHC_ERROR_FLAG_ERROR_BOUND);
} else {
/* Device updated req_id during blocking time
- * with valid timestamp
+ * with valid timestamp and error bound
*/
phc->stats.phc_exp++;
}
@@ -1861,9 +1867,9 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
/* Stalling until the device updates req_id */
while (1) {
if (unlikely(ktime_after(ktime_get(), expire_time))) {
- /* Gave up waiting for updated req_id, PHC enters into
- * blocked state until passing blocking time,
- * during this time any get PHC timestamp will fail with
+ /* Gave up waiting for updated req_id,
+ * PHC enters into blocked state until passing blocking
+ * time, during this time, any request will fail with
* device busy error
*/
ret = -EBUSY;
@@ -1879,14 +1885,15 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
}
/* req_id was updated by the device which indicates that
- * PHC timestamp and error_flags are updated too,
- * checking errors before retrieving timestamp
+ * PHC timestamp, error_bound and error_flags are updated too,
+ * checking error flags before retrieving timestamp and
+ * error_bound values
*/
if (unlikely(resp->error_flags & ENA_PHC_ERROR_FLAGS)) {
- /* Retrieved invalid PHC timestamp, PHC enters into
- * blocked state until passing blocking time,
- * during this time any get PHC timestamp requests
- * will fail with device busy error
+ /* Retrieved timestamp or error bound errors,
+ * PHC enters into blocked state until passing blocking
+ * time, during this time, any request will fail with
+ * device busy error
*/
ret = -EBUSY;
break;
@@ -1894,12 +1901,15 @@ int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
/* PHC timestamp value is returned to the caller */
*timestamp = resp->timestamp;
+ if (error_bound)
+ *error_bound = resp->error_bound;
/* Update statistic on valid PHC timestamp retrieval */
phc->stats.phc_cnt++;
/* This indicates PHC state is active */
phc->system_time = zero_system_time;
+
break;
}
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h
index 64df2c4..fcbff1a 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.h
+++ b/drivers/net/ethernet/amazon/ena/ena_com.h
@@ -216,6 +216,7 @@ struct ena_com_stats_phc {
u64 phc_skp;
u64 phc_err_dv;
u64 phc_err_ts;
+ u64 phc_err_eb;
};
struct ena_com_admin_queue {
@@ -462,9 +463,11 @@ void ena_com_phc_destroy(struct ena_com_dev *ena_dev);
/* ena_com_phc_get_timestamp - Retrieve PHC timestamp
* @ena_dev: ENA communication layer struct
* @timestamp: Retrieved PHC timestamp
+ * @error_bound: maximum possible deviation of the timestamp (nanosecond)
* @return - 0 on success, negative value on failure
*/
-int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp);
+int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp,
+ u32 *error_bound);
/* ena_com_set_mmio_read_mode - Enable/disable the indirect mmio reg read mechanism
* @ena_dev: ENA communication layer struct
diff --git a/drivers/net/ethernet/amazon/ena/ena_debugfs.c b/drivers/net/ethernet/amazon/ena/ena_debugfs.c
index 46ed809..db9d184 100644
--- a/drivers/net/ethernet/amazon/ena/ena_debugfs.c
+++ b/drivers/net/ethernet/amazon/ena/ena_debugfs.c
@@ -32,6 +32,9 @@ static int phc_stats_show(struct seq_file *file, void *priv)
seq_printf(file,
"phc_err_ts: %llu\n",
adapter->ena_dev->phc.stats.phc_err_ts);
+ seq_printf(file,
+ "phc_err_eb: %llu\n",
+ adapter->ena_dev->phc.stats.phc_err_eb);
return 0;
}
diff --git a/drivers/net/ethernet/amazon/ena/ena_phc.c b/drivers/net/ethernet/amazon/ena/ena_phc.c
index c2a3ff1..2bcb5af 100644
--- a/drivers/net/ethernet/amazon/ena/ena_phc.c
+++ b/drivers/net/ethernet/amazon/ena/ena_phc.c
@@ -40,7 +40,8 @@ static int ena_phc_gettimex64(struct ptp_clock_info *clock_info,
ptp_read_system_prets(sts);
rc = ena_com_phc_get_timestamp(phc_info->adapter->ena_dev,
- ×tamp_nsec);
+ ×tamp_nsec,
+ NULL);
ptp_read_system_postts(sts);
--
2.47.3
^ permalink raw reply related
* [PATCH v2 net-next 8/8] net: ena: Implement gettimexattrs64 callback for PTP attributes
From: Arthur Kiyanovski @ 2026-04-30 3:25 UTC (permalink / raw)
To: David Miller, Jakub Kicinski, netdev
Cc: Arthur Kiyanovski, Richard Cochran, Eric Dumazet, Paolo Abeni,
David Woodhouse, Thomas Gleixner, Miroslav Lichvar, Andrew Lunn,
Wen Gu, Xuan Zhuo, David Woodhouse, Yonatan Sarna,
Zorik Machulsky, Alexander Matushevsky, Saeed Bshara, Matt Wilson,
Anthony Liguori, Nafea Bshara, Evgeny Schmeilin, Netanel Belgazal,
Ali Saidi, Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
shuah, vadim.fedorenko
In-Reply-To: <20260430032507.11586-1-akiyano@amazon.com>
Implement the gettimexattrs64 callback in the ENA driver to support
the PTP_SYS_OFFSET_EXTENDED_ATTRS ioctl.
This enables applications to retrieve PHC timestamps with quality
attributes through the standard PTP ioctl interface.
The ENA device currently reports only error_bound.
clock_status and timescale attributes are set to default values.
Signed-off-by: Amit Bernstein <amitbern@amazon.com>
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
drivers/net/ethernet/amazon/ena/ena_phc.c | 59 +++++++++++++++++++----
1 file changed, 49 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/amazon/ena/ena_phc.c b/drivers/net/ethernet/amazon/ena/ena_phc.c
index 2bcb5af..2ce5d45 100644
--- a/drivers/net/ethernet/amazon/ena/ena_phc.c
+++ b/drivers/net/ethernet/amazon/ena/ena_phc.c
@@ -25,6 +25,44 @@ static int ena_phc_feature_enable(struct ptp_clock_info *clock_info,
return -EOPNOTSUPP;
}
+static int ena_phc_gettimexattrs64(struct ptp_clock_info *clock_info,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts,
+ struct ptp_clock_attributes *att)
+{
+ struct ena_phc_info *phc_info =
+ container_of(clock_info, struct ena_phc_info, clock_info);
+ u32 error_bound_nsec;
+ unsigned long flags;
+ u64 timestamp_nsec;
+ int rc;
+
+ spin_lock_irqsave(&phc_info->lock, flags);
+
+ ptp_read_system_prets(sts);
+
+ rc = ena_com_phc_get_timestamp(phc_info->adapter->ena_dev,
+ ×tamp_nsec,
+ &error_bound_nsec);
+
+ ptp_read_system_postts(sts);
+
+ spin_unlock_irqrestore(&phc_info->lock, flags);
+
+ if (rc)
+ return rc;
+
+ *ts = ns_to_timespec64(timestamp_nsec);
+
+ if (att) {
+ att->error_bound = error_bound_nsec;
+ att->status = PTP_CLOCK_STATUS_UNKNOWN;
+ att->timescale = PTP_TIMESCALE_UNKNOWN;
+ }
+
+ return 0;
+}
+
static int ena_phc_gettimex64(struct ptp_clock_info *clock_info,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
@@ -62,16 +100,17 @@ static int ena_phc_settime64(struct ptp_clock_info *clock_info,
}
static struct ptp_clock_info ena_ptp_clock_info = {
- .owner = THIS_MODULE,
- .n_alarm = 0,
- .n_ext_ts = 0,
- .n_per_out = 0,
- .pps = 0,
- .adjtime = ena_phc_adjtime,
- .adjfine = ena_phc_adjfine,
- .gettimex64 = ena_phc_gettimex64,
- .settime64 = ena_phc_settime64,
- .enable = ena_phc_feature_enable,
+ .owner = THIS_MODULE,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .adjtime = ena_phc_adjtime,
+ .adjfine = ena_phc_adjfine,
+ .gettimexattrs64 = ena_phc_gettimexattrs64,
+ .gettimex64 = ena_phc_gettimex64,
+ .settime64 = ena_phc_settime64,
+ .enable = ena_phc_feature_enable,
};
/* Enable/Disable PHC by the kernel, affects on the next init flow */
--
2.47.3
^ permalink raw reply related
* Re: [PATCH net-next 3/4] r8152: Add irq mitigation for RTL8157/9
From: Birger Koblitz @ 2026-04-30 3:36 UTC (permalink / raw)
To: Michal Pecio
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, linux-usb, netdev, linux-kernel,
Chih Kai Hsu
In-Reply-To: <20260429200214.3e8dee67.michal.pecio@gmail.com>
Thanks Michal, for your explanations!
On 29/04/2026 8:02 pm, Michal Pecio wrote:
>>> What does interrupt mitigation do?
>>>
>>> Is this a different name for interrupt coalescence, where the MAC
>>> delays interrupts for a period of time so more packets are in the
>>> receive ring when it does interrupt, so reducing the number of
>>> interrupts, and bigger bursts of packets are processed at once?
>>>
>>
>> I do not understand what the mechanism behind this is, there is no
>> more documentation in the original driver. I experimented with this
>> for some time and the effect that I see is that it prevents
>> interrupts after shutdown.
>
> What do you mean by "after shutdown", driver unbind? You shouldn't be
> seeing URB completions then if the disconnect() method unlinks them.
> And if it doesn't, completions may be using driver data after free.
>
> Or maybe you have pending URBs while calling set_configuration() or
> set_interface(), which is dodgy too but at least not asking for panic.
>
> Other cause of ESHUTDOWN might be serious host controller failure, but
> you would likely get other log noise with that, at least with xhci.
>
> What shows up if you repro with this enabled?
> echo 'module usbcore +p' >/proc/dynamic_debug/control
>
With shutdown, I meant shutting down the driver: the error happens when
unloading the driver using rmmod, e.g. when testing different driver
versions. What I see when turning on debugging is this:
[373042.499758] r8152 2-1:1.0 enx88c9b3b53125: carrier on
[373104.440114] usbcore: deregistering interface driver r8152
[373104.440141] xhci_hcd 0000:0c:00.0: shutdown urb 000000005501f8cc
ep1in-bulk
[373104.440146] xhci_hcd 0000:0c:00.0: shutdown urb 0000000066ae4a92
ep1in-bulk
[373104.440148] xhci_hcd 0000:0c:00.0: shutdown urb 00000000e9728025
ep1in-bulk
[373104.440151] xhci_hcd 0000:0c:00.0: shutdown urb 00000000fa874ca0
ep1in-bulk
[373104.440153] xhci_hcd 0000:0c:00.0: shutdown urb 000000006006ed5d
ep1in-bulk
[373104.440156] xhci_hcd 0000:0c:00.0: shutdown urb 00000000a5bee1e7
ep1in-bulk
[373104.440158] xhci_hcd 0000:0c:00.0: shutdown urb 00000000bc3a3ab0
ep1in-bulk
[373104.440160] xhci_hcd 0000:0c:00.0: shutdown urb 0000000080a63692
ep1in-bulk
[373104.440163] xhci_hcd 0000:0c:00.0: shutdown urb 0000000025af4e6e
ep1in-bulk
[373104.440165] xhci_hcd 0000:0c:00.0: shutdown urb 0000000056d7e76e
ep1in-bulk
[373104.440472] xhci_hcd 0000:0c:00.0: shutdown urb 00000000d8814536
ep3in-intr
[373104.440790] r8152 2-1:1.0 enx88c9b3b53125: Stop submitting intr,
status -108
[373104.479779] r8152 2-1:1.0: rtl8153_unload called
[373104.534682] usbcore: deregistering device driver r8152-cfgselector
[373104.534704] r8152-cfgselector 2-1: unregistering interface 2-1:1.0
[373104.534826] r8152-cfgselector 2-1: usb_disable_device nuking non-ep0
URBs
In the past I have also seen the following, but am not able to reproduce it:
[371283.534041] r8152-cfgselector 2-1: USB disconnect, device number 25
[371283.534470] r8152 2-1:1.0 enx00e04c680023: Stop submitting intr,
status -108
Also, I only see the issue on slow 5GBit USB-C connections, sometimes
with the RTL8157, basically every time with the RTL8159, and so far
never on a 20GBit USB-C connection, so the mitigation is probably some
kind of interrupt coalescing.
Birger
^ permalink raw reply
* [PATCH 0/3] net: mana: Fix mana_destroy_rxq() cleanup for partial RXQ init
From: Dipayaan Roy @ 2026-04-30 3:57 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, dipayanroy, leitao, kees,
john.fastabend, hawk, bpf, daniel, ast, sdf, yury.norov
When mana_create_rxq() fails partway through initialization (e.g. the
hardware rejects the WQ object creation), the error path calls
mana_destroy_rxq() to tear down a partially-initialized RXQ.
This exposed multiple issues in mana_destroy_rxq() path, as it assumed
the RXQ was always fully initialized, leading to multiple issues:
1. xdp_rxq_info_unreg() was called on an unregistered xdp_rxq,
triggering a WARN_ON ("Driver BUG") in net/core/xdp.c.
2. mana_destroy_wq_obj() was called with INVALID_MANA_HANDLE,
sending a bogus destroy command to the hardware.
3. mana_deinit_cq() was called twice — once inside mana_destroy_rxq()
and again in mana_create_rxq()'s error path — causing a
use-after-free since mana_destroy_rxq() frees the rxq first.
This was observed during ethtool ring parameter changes when the
hardware returned an error creating the RXQ. This series makes
mana_destroy_rxq() safe to call at any stage of RXQ initialization
by guarding each teardown step, and removes the redundant cleanup
in mana_create_rxq().
Dipayaan Roy (3):
net: mana: check xdp_rxq registration before unreg in
mana_destroy_rxq()
net: mana: Skip WQ object destruction for uninitialized RXQ
net: mana: remove double CQ cleanup in mana_create_rxq error path
drivers/net/ethernet/microsoft/mana/mana_en.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH 1/3] net: mana: check xdp_rxq registration before unreg in mana_destroy_rxq()
From: Dipayaan Roy @ 2026-04-30 3:57 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, dipayanroy, leitao, kees,
john.fastabend, hawk, bpf, daniel, ast, sdf, yury.norov
In-Reply-To: <20260430035935.1859220-1-dipayanroy@linux.microsoft.com>
When mana_create_rxq() fails at mana_create_wq_obj() or any step before
xdp_rxq_info_reg() is called, the error path jumps to `out:` which calls
mana_destroy_rxq(). mana_destroy_rxq() unconditionally calls
xdp_rxq_info_unreg() on xilinx xdp_rxq that was never registered,
triggering a WARN_ON in net/core/xdp.c:
mana 7870:00:00.0: HWC: Failed hw_channel req: 0xc000009a
mana 7870:00:00.0 eth7: Failed to create RXQ: err = -71
Driver BUG
WARNING: CPU: 442 PID: 491615 at ../net/core/xdp.c:150 xdp_rxq_info_unreg+0x44/0x70
Modules linked in: tcp_bbr xsk_diag udp_diag raw_diag unix_diag af_packet_diag netlink_diag nf_tables nfnetlink tcp_diag inet_diag binfmt_misc rpcsec_gss_krb5 nfsv3 nfs_acl auth_rpcgss nfsv4 dns_resolver nfs lockd ext4 grace crc16 iscsi_tcp mbcache fscache libiscsi_tcp jbd2 netfs rpcrdma af_packet sunrpc rdma_ucm ib_iser rdma_cm iw_cm iscsi_ibft ib_cm iscsi_boot_sysfs libiscsi rfkill scsi_transport_iscsi mana_ib ib_uverbs ib_core mana hyperv_drm(X) drm_shmem_helper intel_rapl_msr drm_kms_helper intel_rapl_common syscopyarea nls_iso8859_1 sysfillrect intel_uncore_frequency_common nls_cp437 vfat fat nfit sysimgblt libnvdimm hv_netvsc(X) hv_utils(X) fb_sys_fops hv_balloon(X) joydev fuse drm dm_mod configfs ip_tables x_tables xfs libcrc32c sd_mod nvme nvme_core nvme_common t10_pi crc64_rocksoft_generic crc64_rocksoft crc64 hid_generic serio_raw pci_hyperv(X) hv_storvsc(X) scsi_transport_fc hyperv_keyboard(X) hid_hyperv(X) pci_hyperv_intf(X) crc32_pclmul
crc32c_intel ghash_clmulni_intel aesni_intel crypto_simd cryptd hv_vmbus(X) softdog sg scsi_mod efivarfs
Supported: Yes, External
CPU: 442 PID: 491615 Comm: ethtool Kdump: loaded Tainted: G X 5.14.21-150500.55.136-default #1 SLE15-SP5 a627be1b53abbfd64ad16b2685e4308c52847f42
Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 07/25/2025
RIP: 0010:xdp_rxq_info_unreg+0x44/0x70
Code: e8 91 fe ff ff c7 43 0c 02 00 00 00 48 c7 03 00 00 00 00 5b c3 cc cc cc cc e9 58 3a 1c 00 48 c7 c7 f6 5f 19 97 e8 5c a4 7e ff <0f> 0b 83 7b 0c 01 74 ca 48 c7 c7 d9 5f 19 97 e8 48 a4 7e ff 0f 0b
RSP: 0018:ff3df6c8f7207818 EFLAGS: 00010286
RAX: 0000000000000000 RBX: ff30d89f94808a80 RCX: 0000000000000027
RDX: 0000000000000000 RSI: 0000000000000002 RDI: ff30d94bdcca2908
RBP: 0000000000080000 R08: ffffffff98ed11a0 R09: ff3df6c8f72077a0
R10: dead000000000100 R11: 000000000000000a R12: 0000000000000000
R13: 0000000000002000 R14: 0000000000040000 R15: ff30d89f94800000
FS: 00007fe6d8432b80(0000) GS:ff30d94bdcc80000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fe6d81a89b1 CR3: 00000b3b6d578001 CR4: 0000000000371ee0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400
Call Trace:
<TASK>
mana_destroy_rxq+0x5b/0x2f0 [mana 267acf7006bcb696095bba4d810643d1db3b9e94]
mana_create_rxq.isra.55+0x3db/0x720 [mana 267acf7006bcb696095bba4d810643d1db3b9e94]
? simple_lookup+0x36/0x50
? current_time+0x42/0x80
? __d_free_external+0x30/0x30
mana_alloc_queues+0x32a/0x470 [mana 267acf7006bcb696095bba4d810643d1db3b9e94]
? _raw_spin_unlock+0xa/0x30
? d_instantiate.part.29+0x2e/0x40
? _raw_spin_unlock+0xa/0x30
? debugfs_create_dir+0xe4/0x140
mana_attach+0x5c/0xf0 [mana 267acf7006bcb696095bba4d810643d1db3b9e94]
mana_set_ringparam+0xd5/0x1a0 [mana 267acf7006bcb696095bba4d810643d1db3b9e94]
ethnl_set_rings+0x292/0x320
genl_family_rcv_msg_doit.isra.15+0x11b/0x150
genl_rcv_msg+0xe3/0x1e0
? rings_prepare_data+0x80/0x80
? genl_family_rcv_msg_doit.isra.15+0x150/0x150
netlink_rcv_skb+0x50/0x100
genl_rcv+0x24/0x40
netlink_unicast+0x1b6/0x280
netlink_sendmsg+0x365/0x4d0
sock_sendmsg+0x5f/0x70
__sys_sendto+0x112/0x140
__x64_sys_sendto+0x24/0x30
do_syscall_64+0x5b/0x80
? handle_mm_fault+0xd7/0x290
? do_user_addr_fault+0x2d8/0x740
? exc_page_fault+0x67/0x150
entry_SYSCALL_64_after_hwframe+0x6b/0xd5
RIP: 0033:0x7fe6d8122f06
Code: 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 11 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 72 f3 c3 41 57 41 56 4d 89 c7 41 55 41 54 41
RSP: 002b:00007fff2b66b068 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
RAX: ffffffffffffffda RBX: 000055771123d2a0 RCX: 00007fe6d8122f06
RDX: 0000000000000034 RSI: 000055771123d3b0 RDI: 0000000000000003
RBP: 00007fff2b66b100 R08: 00007fe6d8203360 R09: 000000000000000c
R10: 0000000000000000 R11: 0000000000000246 R12: 000055771123d350
R13: 000055771123d340 R14: 0000000000000000 R15: 00007fff2b66b2b0
</TASK>
Guard the xdp_rxq_info_unreg() call with xdp_rxq_info_is_reg() so that
mana_destroy_rxq() is safe to call regardless of how far initialization
progressed.
Fixes: ed5356b53f07 ("net: mana: Add XDP support")
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index a654b3699c4c..dfb4ba9f7664 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2520,7 +2520,9 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
napi_disable_locked(napi);
netif_napi_del_locked(napi);
}
- xdp_rxq_info_unreg(&rxq->xdp_rxq);
+
+ if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
+ xdp_rxq_info_unreg(&rxq->xdp_rxq);
mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] net: mana: Skip WQ object destruction for uninitialized RXQ
From: Dipayaan Roy @ 2026-04-30 3:57 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, dipayanroy, leitao, kees,
john.fastabend, hawk, bpf, daniel, ast, sdf, yury.norov
In-Reply-To: <20260430035935.1859220-1-dipayanroy@linux.microsoft.com>
In mana_destroy_rxq(), mana_destroy_wq_obj() is called unconditionally
even when the WQ object was never created (rxobj is still
INVALID_MANA_HANDLE). When mana_create_rxq() fails before
mana_create_wq_obj() succeeds, the error path calls mana_destroy_rxq()
which sends a bogus destroy command to the hardware:
mana 7870:00:00.0: HWC: Failed hw_channel req: 0x1d
mana 7870:00:00.0: Failed to send mana message: -71, 0x1d
mana 7870:00:00.0 eth7: Failed to destroy WQ object: -71
Guard mana_destroy_wq_obj() with an INVALID_MANA_HANDLE check so that
mana_destroy_rxq() is safe to call at any stage of RXQ initialization.
Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index dfb4ba9f7664..f2a6ea162dc3 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2524,7 +2524,8 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
xdp_rxq_info_unreg(&rxq->xdp_rxq);
- mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
+ if (rxq->rxobj != INVALID_MANA_HANDLE)
+ mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
mana_deinit_cq(apc, &rxq->rx_cq);
--
2.43.0
^ permalink raw reply related
* [PATCH 3/3] net: mana: remove double CQ cleanup in mana_create_rxq error path
From: Dipayaan Roy @ 2026-04-30 3:57 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, dipayanroy, leitao, kees,
john.fastabend, hawk, bpf, daniel, ast, sdf, yury.norov
In-Reply-To: <20260430035935.1859220-1-dipayanroy@linux.microsoft.com>
In mana_create_rxq(), the error cleanup path calls mana_destroy_rxq()
followed by mana_deinit_cq(). This is incorrect for two reasons:
1. mana_destroy_rxq() already calls mana_deinit_cq() internally,
so the CQ's GDMA queue is destroyed twice.
2. mana_destroy_rxq() frees the rxq via kfree(rxq) before returning.
The subsequent mana_deinit_cq(apc, cq) then operates on freed memory
since cq points to &rxq->rx_cq, which is embedded in the
already-freed rxq structure — a use-after-free.
Remove the redundant mana_deinit_cq() call from the error path since
mana_destroy_rxq() already handles CQ cleanup. mana_deinit_cq() is
itself safe for an uninitialized CQ as it checks for a NULL gdma_cq
before proceeding.
Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index f2a6ea162dc3..9afc786b297a 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2799,9 +2799,6 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
mana_destroy_rxq(apc, rxq, false);
- if (cq)
- mana_deinit_cq(apc, cq);
-
return NULL;
}
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v5 net 01/10] octeontx2-af: npc: cn20k: Propagate MCAM key-type errors on cn20k
From: Ratheesh Kannoth @ 2026-04-30 4:05 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Suman Ghosh, Dan Carpenter
In-Reply-To: <20260429022722.1110289-2-rkannoth@marvell.com>
On 2026-04-29 at 07:57:13, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_mcam_idx_2_key_type() can fail; callers used to ignore it and still
> used kw_type when enabling, configuring, copying, and reading MCAM entries.
> That could program or decode hardware with an undefined key type.
>
> Return -EINVAL when key-type lookup fails. Return -EINVAL from
> npc_cn20k_copy_mcam_entry() when src and dest key types differ instead of
> failing silently.
>
> Change npc_cn20k_{enable,config,copy,read}_mcam_entry() to return int on
> success or error. Thread those errors through the cn20k MCAM write and read
> mbox handlers, the cn20k baseline steer read path, NPC defrag move
> (disable/copy/enable with dev_err and -EFAULT), and the DMAC update path in
> rvu_npc_fs.c.
>
> Make npc_copy_mcam_entry() return int so the cn20k branch can return
> npc_cn20k_copy_mcam_entry() without a void/int mismatch, and fail
> NPC_MCAM_SHIFT_ENTRY when copy fails.
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> index 7291fdb89b03..7170dcf26200 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
[ ... ]
> @@ -1375,11 +1395,13 @@ int rvu_mbox_handler_npc_cn20k_mcam_alloc_and_write_entry(struct rvu *rvu,
> struct npc_mcam_alloc_and_write_entry_rsp *rsp)
> {
> struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
> + struct npc_mcam_free_entry_req free_req = { 0 };
> struct npc_mcam_alloc_entry_req entry_req;
>This isn't a bug introduced here, but entry_req is allocated on the stack
>and is not zero-initialized. Its kw_type field does not appear to be set
>before calling rvu_mbox_handler_npc_mcam_alloc_entry().
>Could this uninitialized stack garbage lead to unpredictable bounds-check
>failures or random mcam allocation errors?
I see your concern regarding the uninitialized entry_req. The reason it was left as-is is that this patch
focuses specifically on the MCAM key-type error propagation logic. However, I agree that leaving stack garbage is suboptimal.
If you prefer not to bundle this with the current Smatch fix
> @@ -3607,9 +3640,30 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
> NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(midx,
> bank));
>
> - npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false);
> - npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx);
> - npc_cn20k_enable_mcam_entry(rvu, blkaddr, new_midx, true);
> + /* If bug happened during copy/enable mcam, then there is a bug in allocation
> + * algorithm itself. There is no point in rewinding and returning, as it
> + * will face further issue. Return error after printing error
> + */
> + if (npc_cn20k_enable_mcam_entry(rvu, blkaddr, old_midx, false)) {
> + dev_err(rvu->dev,
> + "%s: Error happened while disabling old_mid=%u\n",
> + __func__, old_midx);
> + return -EFAULT;
> + }
> +
> + if (npc_cn20k_copy_mcam_entry(rvu, blkaddr, old_midx, new_midx)) {
> + dev_err(rvu->dev,
> + "%s: Error happened while copying old_midx=%u new_midx=%u\n",
> + __func__, old_midx, new_midx);
> + return -EFAULT;
> + }
>When these early returns execute, the software vidx map has already been
>redirected to new_midx via a preceding call to npc_vidx_maps_modify().
>Since the early returns skip the remaining bookkeeping steps (updating
>mcam->entry2pfvf_map, freeing old_midx, and updating counts), does this leave
>the system in a corrupted state?
>Would the vidx now point to a new_midx that the user does not officially own
>(causing NPC_MCAM_PERM_DENIED on future accesses), while old_midx is left
>disabled and permanently leaked?
understand the concern regarding the vidx map falling out of sync. However, npc_defrag_move_vdx_to_free runs under a mutex, and
a failure during the copy/enable phase indicates the NPC block has entered a non-deterministic state.
In this specific 'should-never-happen' scenario, attempting a graceful software rewind could mask a critical fault or lead to further exceptions.
My intention with this Smatch fix was to ensure the error is at least caught and logged rather than silently ignored.
I can address a full transactional rollback mechanism in a separate hardening series for net-next.
But issue is graceful rollback can also fail as it is kind of another defrag process.
> @@ -2038,8 +2040,12 @@ void npc_mcam_enable_flows(struct rvu *rvu, u16 target)
> continue;
> }
>
> - if (rule->vfvlan_cfg)
> - npc_update_dmac_value(rvu, blkaddr, rule, pfvf);
> + if (rule->vfvlan_cfg) {
> + if (npc_update_dmac_value(rvu, blkaddr, rule, pfvf))
> + dev_err(rvu->dev,
> + "Update dmac failed for %u, target=%#x\n",
> + rule->entry, target);
> + }
>If npc_update_dmac_value() fails and returns an error like -EINVAL, execution
>falls through and logs the error, but continues processing the current rule.
>The code then computes a hardware offset via NPC_AF_MCAMEX_BANKX_ACTION()
>and unconditionally performs a direct hardware write using rule->entry.
>If rule->entry happens to be invalid or out-of-bounds, could this fall-through
>cause unrelated device registers to be corrupted, or trigger a data abort?
>Even though a later patch in this series hardens some helpers, is a continue
>statement missing here to protect the immediate rvu_write64() that follows?
>Additionally, this is not a regression in this patch, but I noticed that
>list_for_each_entry() is used to iterate over mcam->mcam_rules while
>holding mcam->lock.
>If npc_update_dmac_value() is called, it explicitly drops mcam->lock before
>invoking the mailbox handler.
>If a concurrent thread acquires the lock and deletes the current rule while
>it is dropped, will the list iteration resume with a use-after-free on the
>freed rule pointer?
>Should a safe list iteration macro be used instead, combined with reference
>counting to preserve the rule?
I acknowledge that dropping mcam->lock during list_for_each_entry is a significant architectural vulnerability.
However, fixing this properly requires moving to a reference-counted rule model or an RCU-based iteration to prevent regressions.
Since this series is a targeted bug fix for net focused on Smatch errors, I believe a full locking refactor is
too high-risk for this specific pull request. Will work on hardening patch to net-next.
^ permalink raw reply
* Re: [PATCH 2/2] pinctrl: qcom: Add Shikra pinctrl driver
From: Maulik Shah (mkshah) @ 2026-04-30 4:06 UTC (permalink / raw)
To: Komal Bajaj, Bjorn Andersson, Linus Walleij, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Cochran
Cc: linux-arm-msm, linux-gpio, devicetree, linux-kernel, netdev
In-Reply-To: <20260429-shikra-pinctrl-v1-2-1b4bb2b3a8d6@oss.qualcomm.com>
On 4/29/2026 6:41 PM, Komal Bajaj wrote:
> Add pinctrl driver for TLMM block found in Shikra SoC.
[...]
> +#define UFS_RESET(pg_name, ctl, io) \
> + { \
> + .grp = PINCTRL_PINGROUP(#pg_name, \
> + pg_name##_pins, \
> + ARRAY_SIZE(pg_name##_pins)), \
> + .ctl_reg = ctl, \
> + .io_reg = io, \
> + .intr_cfg_reg = 0, \
> + .intr_status_reg = 0, \
> + .mux_bit = -1, \
> + .pull_bit = 3, \
> + .drv_bit = 0, \
> + .oe_bit = -1, \
> + .in_bit = -1, \
> + .out_bit = 0, \
> + .intr_enable_bit = -1, \
> + .intr_status_bit = -1, \
> + .intr_target_bit = -1, \
> + .intr_raw_status_bit = -1, \
> + .intr_polarity_bit = -1, \
> + .intr_detection_bit = -1, \
> + .intr_detection_width = -1, \
> + }
UFS_RESET macro is not used anywhere in the file, please remove it.
I assume the macro keeps getting added since the file pinctrl-<target> is
fully/partially auto generated. Would be good to fix auto generation to
avoid getting this added as default in future.
The unused ones were removed via [1].
[1] https://lore.kernel.org/all/4429f44e-f7e5-449c-824c-83daa339b383@oss.qualcomm.com/
[...]
> +static const struct msm_gpio_wakeirq_map shikra_mpm_map[] = {
> + {1, 9}, {2, 31}, {5, 49}, {6, 53}, {9, 72}, {10, 10},
It would be better to have spacing before/after brackets inline with other pinctrl drivers.
{1, 9}, should be { 1, 9 }.
> + {12, 22}, {14, 26}, {17, 29}, {18, 24}, {20, 32}, {22, 33},
> + {25, 34}, {27, 35}, {28, 36}, {29, 37}, {30, 38}, {31, 39},
> + {32, 40}, {33, 41}, {38, 42}, {40, 43}, {43, 44}, {44, 45},
> + {45, 46}, {46, 47}, {47, 48}, {48, 60}, {50, 50}, {51, 51},
> + {52, 61}, {53, 62}, {57, 52}, {58, 63}, {60, 54}, {63, 64},
> + {73, 55}, {74, 56}, {75, 57}, {77, 3}, {80, 4}, {84, 5},
> + {85, 67}, {86, 69}, {88, 70}, {89, 71}, {90, 73}, {91, 74},
> + {92, 75}, {93, 76}, {94, 77}, {95, 78}, {97, 79}, {99, 80},
> + {100, 11}, {101, 13}, {102, 14}, {103, 15}, {106, 16}, {108, 17},
> + {112, 18}, {116, 19}, {117, 20}, {119, 21}, {120, 23}, {136, 25},
> + {159, 27}, {161, 28},
> +};
> +
Thanks,
Maulik
^ permalink raw reply
* Re: [PATCH] [PATCH net] tipc: fix UAF race in tipc_mon_peer_up/down/remove_peer vs bearer teardown
From: kernel test robot @ 2026-04-30 4:07 UTC (permalink / raw)
To: SnailSploit | Kai Aizen, netdev
Cc: oe-kbuild-all, tipc-discussion, jmaloy, ying.xue, kuba, pabeni,
stable, Kai Aizen
In-Reply-To: <20260415061211.45530-1-95986478+SnailSploit@users.noreply.github.com>
Hi SnailSploit,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net/main]
url: https://github.com/intel-lab-lkp/linux/commits/SnailSploit-Kai-Aizen/tipc-fix-UAF-race-in-tipc_mon_peer_up-down-remove_peer-vs-bearer-teardown/20260425-075205
base: net/main
patch link: https://lore.kernel.org/r/20260415061211.45530-1-95986478%2BSnailSploit%40users.noreply.github.com
patch subject: [PATCH] [PATCH net] tipc: fix UAF race in tipc_mon_peer_up/down/remove_peer vs bearer teardown
config: arc-randconfig-002-20260430 (https://download.01.org/0day-ci/archive/20260430/202604301148.jfXKC9HF-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260430/202604301148.jfXKC9HF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604301148.jfXKC9HF-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> net/tipc/monitor.c:112:29: warning: 'tipc_monitor_rtnl' defined but not used [-Wunused-function]
static struct tipc_monitor *tipc_monitor_rtnl(struct net *net, int bearer_id)
^~~~~~~~~~~~~~~~~
vim +/tipc_monitor_rtnl +112 net/tipc/monitor.c
110
111 /* tipc_monitor_rtnl - dereference monitors[] from RTNL-held control path. */
> 112 static struct tipc_monitor *tipc_monitor_rtnl(struct net *net, int bearer_id)
113 {
114 return rtnl_dereference(tipc_net(net)->monitors[bearer_id]);
115 }
116
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] page_pool: fix memory-provider leak in page_pool_create_percpu() error path
From: patchwork-bot+netdevbpf @ 2026-04-30 4:10 UTC (permalink / raw)
To: Hasan Basbunar
Cc: hawk, ilias.apalodimas, kuba, pabeni, edumazet, davem, horms,
almasrymina, asml.silence, kaiyuanz, willemb, netdev,
linux-kernel
In-Reply-To: <20260428170739.34881-1-basbunarhasan@gmail.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 28 Apr 2026 19:07:39 +0200 you wrote:
> When page_pool_create_percpu() fails on page_pool_list(), it falls
> through to its err_uninit: label, which calls page_pool_uninit().
> At that point page_pool_init() has already taken two references
> when the user requested PP_FLAG_ALLOW_UNREADABLE_NETMEM:
>
> pool->mp_ops->init(pool)
> static_branch_inc(&page_pool_mem_providers);
>
> [...]
Here is the summary with links:
- page_pool: fix memory-provider leak in page_pool_create_percpu() error path
https://git.kernel.org/netdev/net/c/5ef343614db7
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v5 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
From: Ratheesh Kannoth @ 2026-04-30 4:10 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Dan Carpenter, Simon Horman
In-Reply-To: <20260429022722.1110289-4-rkannoth@marvell.com>
On 2026-04-29 at 07:57:15, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_defrag_alloc_free_slots() allocates MCAM indexes in up to two passes on
> bank0 then bank1. On failure it rolls back by freeing entries already
> placed in save[].
>
> __npc_subbank_alloc() can return a negative errno while only part of the
> indexes are valid. The rollback loop used rc for
> npc_mcam_idx_2_subbank_idx() as well, so a successful lookup stored zero in
> rc and a later __npc_subbank_free() failure could still end with return 0
> when the allocation path had also left rc at zero (for example shortfall
> after zero return values from the alloc helpers).
>
> Jump to the rollback path immediately when either __npc_subbank_alloc()
> call fails, preserving its errno. If both calls succeed but the total
> allocated count is still less than cnt, set rc to -ENOSPC before rollback.
> Use a separate err variable for npc_mcam_idx_2_subbank_idx() so a
> successful lookup no longer clears a non-zero rc from the allocation phase.
>
>>could the commit message be updated, or are there missing checks for the
>>return value of __npc_subbank_alloc() in the code?
We clearly mentioned that if both fails rc is set to -ENOSPC.
> @@ -3529,6 +3530,7 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
> NPC_MCAM_LOWER_PRIO,
> false, cnt, save, cnt, true,
> &alloc_cnt1);
> +
> if (alloc_cnt1 < cnt) {
> rc = __npc_subbank_alloc(rvu, sb,
> NPC_MCAM_KEY_X2, sb->b1b,
>If the first __npc_subbank_alloc() call fails with an error like -ENOMEM,
>alloc_cnt1 is set to 0.
>Would this make the alloc_cnt1 < cnt check evaluate to true, causing the
>code to attempt the second allocation instead of jumping to the rollback
>path immediately?
Roll back is already done inside __npc_subbank_alloc(). So no need to rollback.
> @@ -3544,15 +3546,17 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
> dev_err(rvu->dev,
> "%s: Failed to alloc cnt=%u alloc_cnt1=%u alloc_cnt2=%u\n",
> __func__, cnt, alloc_cnt1, alloc_cnt2);
> + rc = -ENOSPC;
> goto fail_free_alloc;
> }
>If the allocation fails and sets rc to the actual error code, won't this
>block unconditionally overwrite the preserved errno with -ENOSPC before
>jumping to the rollback path?
You are correct that if the first call returns an error, alloc_cnt1 is 0 and we proceed to the second call. This is intentional. The defrag logic
attempts to gather the required total entries (cnt) across multiple sub-banks. If the first bank fails or is full,
we must still try the second bank to see if the combined total can satisfy the request. Since __npc_subbank_alloc()
handles its own internal rollback on failure, there is no leaked state when we 'fall through' to the second attempt.The use of -ENOSPC here is intentional
for the defrag context. Even if a sub-call returned -ENOMEM, the high-level failure at this stage is that the hardware simply does not have
the contiguous space required to perform the defrag move.
^ permalink raw reply
* Re: [PATCH v5 net 04/10] octeontx2-af: npc: cn20k: Fix target map and rule
From: Ratheesh Kannoth @ 2026-04-30 4:13 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev
In-Reply-To: <20260429022722.1110289-5-rkannoth@marvell.com>
On 2026-04-29 at 07:57:16, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_defrag_move_vdx_to_free() disables, copies, and enables the MCAM entry
> at a new index but previously left entry2target_pffunc[] and the mcam_rules
> list still keyed to the old index. Copy the target PF association to the
> new slot, clear the old one, and retarget the rule entry so software state
> matches the relocated hardware context.
>
> Fixes: 645c6e3c1999 ("octeontx2-af: npc: cn20k: virtual index support")
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
@@ -3723,8 +3724,21 @@ int npc_defrag_move_vdx_to_free(struct rvu *rvu,
> mcam->entry2pfvf_map[new_midx] = pcifunc;
> /* Counter is not preserved */
> mcam->entry2cntr_map[new_midx] = new_midx;
> + target_pf = mcam->entry2target_pffunc[old_midx];
>Is mcam->entry2target_pffunc always initialized before we read from it here?
>If it was allocated with kmalloc_array() during driver initialization and no
>target PF was explicitly configured for this MCAM entry, could this read
>uninitialized heap memory and copy it to the new index?
The npc_defrag_move_vdx_to_free function only operates on entries that are currently 'in-use' and
being relocated to optimize space. Because the target PF configuration is a prerequisite for an
entry to be considered active in the MCAM pipeline, these fields are guaranteed to be
populated by the time a defrag move is triggered.
> + mcam->entry2target_pffunc[new_midx] = target_pf;
> + mcam->entry2target_pffunc[old_midx] = NPC_MCAM_INVALID_MAP;
> +
> npc_mcam_set_bit(mcam, new_midx);
>
> + /* Note: list order is not functionally required for mcam_rules */
> + list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
> + if (rule->entry != old_midx)
> + continue;
> +
> + rule->entry = new_midx;
>If npc_add_to_pf_maps() fails earlier in this loop, the function returns an
>error without updating these software tracking maps. At that failure point,
>the hardware rule at old_midx has already been disabled and its subbank marked
>as free via __npc_subbank_free().
>Since the hardware subbank is free, could the hardware allocation later
>assign old_midx to a completely new user while our mcam_rules list still
>points to it?
In this specific 'should-never-happen' scenario, attempting a graceful software rewind could mask a critical fault or lead to
further exceptions. My intention with this Smatch fix was to ensure smatch fix, is at least caught and logged rather than silently ignored.
I can address a full transactional rollback mechanism in a separate hardening series for net-next. But issue is gracefull rollback
can also fail as it is kind of another defrag process. or may be we can copy to new entries but not free the existing entries, that would be a
enhancement request for net-next.
>If the old rule's owner later modifies or deletes it, could this cause a
>resource collision and inadvertently destroy the newly allocated rule?
No this wont happen, mbox messages are processed by AF driver sequentially. More than that
mcam->lock mutex is already acquired before all these operations.
^ permalink raw reply
* Re: [PATCH 3/3] net: mana: remove double CQ cleanup in mana_create_rxq error path
From: Aditya Garg @ 2026-04-30 4:14 UTC (permalink / raw)
To: Dipayaan Roy, kys, haiyangz, wei.liu, decui, andrew+netdev, davem,
edumazet, kuba, pabeni, leon, longli, kotaranov, horms,
shradhagupta, ssengar, ernis, shirazsaleem, linux-hyperv, netdev,
linux-kernel, linux-rdma, stephen, jacob.e.keller, dipayanroy,
leitao, kees, john.fastabend, hawk, bpf, daniel, ast, sdf,
yury.norov
In-Reply-To: <20260430035935.1859220-4-dipayanroy@linux.microsoft.com>
On 30-04-2026 09:27, Dipayaan Roy wrote:
> In mana_create_rxq(), the error cleanup path calls mana_destroy_rxq()
> followed by mana_deinit_cq(). This is incorrect for two reasons:
>
> 1. mana_destroy_rxq() already calls mana_deinit_cq() internally,
> so the CQ's GDMA queue is destroyed twice.
>
> 2. mana_destroy_rxq() frees the rxq via kfree(rxq) before returning.
> The subsequent mana_deinit_cq(apc, cq) then operates on freed memory
> since cq points to &rxq->rx_cq, which is embedded in the
> already-freed rxq structure — a use-after-free.
>
> Remove the redundant mana_deinit_cq() call from the error path since
> mana_destroy_rxq() already handles CQ cleanup. mana_deinit_cq() is
> itself safe for an uninitialized CQ as it checks for a NULL gdma_cq
> before proceeding.
>
> Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
> Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
> ---
> drivers/net/ethernet/microsoft/mana/mana_en.c | 3 ---
> 1 file changed, 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
> index f2a6ea162dc3..9afc786b297a 100644
> --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
> +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> @@ -2799,9 +2799,6 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
>
> mana_destroy_rxq(apc, rxq, false);
>
> - if (cq)
> - mana_deinit_cq(apc, cq);
> -
> return NULL;
> }
>
Reviewed-by: Aditya Garg <gargaditya@linux.microsoft.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox