[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260115-ksz8463-ptp-v1-8-bcfe2830cf50@bootlin.com>
Date: Thu, 15 Jan 2026 16:57:07 +0100
From: "Bastien Curutchet (Schneider Electric)" <bastien.curutchet@...tlin.com>
To: Woojung Huh <woojung.huh@...rochip.com>, UNGLinuxDriver@...rochip.com,
Andrew Lunn <andrew@...n.ch>, Vladimir Oltean <olteanv@...il.com>,
"David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>,
Richard Cochran <richardcochran@...il.com>, Simon Horman <horms@...nel.org>
Cc: Pascal Eberhard <pascal.eberhard@...com>,
Miquèl Raynal <miquel.raynal@...tlin.com>,
Thomas Petazzoni <thomas.petazzoni@...tlin.com>, netdev@...r.kernel.org,
linux-kernel@...r.kernel.org,
"Bastien Curutchet (Schneider Electric)" <bastien.curutchet@...tlin.com>
Subject: [PATCH net-next 8/8] net: dsa: microchip: Add two-step PTP support
for KSZ8463
The KSZ8463 switch supports PTP but it's not supported by driver.
Add L2 two-step PTP support for the KSZ8463. IPv4 and IPv6 layers aren't
supported. Neither is one-step PTP.
The pdelay_req and pdelay_resp timestamps share one interrupt bit status.
So introduce last_tx_is_pdelayresp to keep track of the last sent event
type. Use it to retrieve the relevant timestamp when the interrupt is
caught.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@...tlin.com>
---
drivers/net/dsa/microchip/ksz8.c | 15 ++--------
drivers/net/dsa/microchip/ksz8_reg.h | 1 +
drivers/net/dsa/microchip/ksz_common.c | 1 +
drivers/net/dsa/microchip/ksz_common.h | 1 +
drivers/net/dsa/microchip/ksz_ptp.c | 52 ++++++++++++++++++++++++++-------
drivers/net/dsa/microchip/ksz_ptp_reg.h | 4 +++
6 files changed, 50 insertions(+), 24 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
index a05527899b8bab6d53509ba38c58101b79e98ee5..cec76965def71320abeb77f550f37af7dcb96d63 100644
--- a/drivers/net/dsa/microchip/ksz8.c
+++ b/drivers/net/dsa/microchip/ksz8.c
@@ -143,9 +143,9 @@ int ksz8_reset_switch(struct ksz_device *dev)
KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, false);
} else if (ksz_is_ksz8463(dev)) {
ksz_cfg(dev, KSZ8463_REG_SW_RESET,
- KSZ8463_GLOBAL_SOFTWARE_RESET, true);
+ KSZ8463_GLOBAL_SOFTWARE_RESET | KSZ8463_PTP_SOFTWARE_RESET, true);
ksz_cfg(dev, KSZ8463_REG_SW_RESET,
- KSZ8463_GLOBAL_SOFTWARE_RESET, false);
+ KSZ8463_GLOBAL_SOFTWARE_RESET | KSZ8463_PTP_SOFTWARE_RESET, false);
} else {
/* reset switch */
ksz_write8(dev, REG_POWER_MANAGEMENT_1,
@@ -1762,17 +1762,6 @@ void ksz8_config_cpu_port(struct dsa_switch *ds)
KSZ8463_REG_DSP_CTRL_6,
COPPER_RECEIVE_ADJUSTMENT, 0);
}
-
- /* Turn off PTP function as the switch's proprietary way of
- * handling timestamp is not supported in current Linux PTP
- * stack implementation.
- */
- regmap_update_bits(ksz_regmap_16(dev),
- KSZ8463_PTP_MSG_CONF1,
- PTP_ENABLE, 0);
- regmap_update_bits(ksz_regmap_16(dev),
- KSZ8463_PTP_CLK_CTRL,
- PTP_CLK_ENABLE, 0);
}
}
diff --git a/drivers/net/dsa/microchip/ksz8_reg.h b/drivers/net/dsa/microchip/ksz8_reg.h
index 332408567b473c141c3695328a524f257f2cfc70..0558740ae57738fa7e4a8f3f429254033c54af12 100644
--- a/drivers/net/dsa/microchip/ksz8_reg.h
+++ b/drivers/net/dsa/microchip/ksz8_reg.h
@@ -765,6 +765,7 @@
#define KSZ8463_REG_SW_RESET 0x126
#define KSZ8463_GLOBAL_SOFTWARE_RESET BIT(0)
+#define KSZ8463_PTP_SOFTWARE_RESET BIT(2)
#define KSZ8463_PTP_CLK_CTRL 0x600
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 5141343d2f40bbd380c0b52f6919b842fb71a8fd..55e3fa4791078cb099e236e6e5a29515727ed8ab 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -1512,6 +1512,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.supports_mii = {false, false, true},
.supports_rmii = {false, false, true},
.internal_phy = {true, true, false},
+ .ptp_capable = true,
},
[KSZ8563] = {
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index dfbc3d13daca8d7a8b9d3ffe6a7c1ec9927863f2..1fface82086eed87749d4702b046fcab313663e9 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -150,6 +150,7 @@ struct ksz_port {
struct kernel_hwtstamp_config tstamp_config;
bool hwts_tx_en;
bool hwts_rx_en;
+ bool last_tx_is_pdelayresp;
struct ksz_irq ptpirq;
struct ksz_ptp_irq ptpmsg_irq[3];
ktime_t tstamp_msg;
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index fcc2a7d50909c4e6a8cf87a3013c3c311c1714b0..dc77c83dc049f16f76e3138708f5cbd70ad70367 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -308,15 +308,20 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct kernel_ethtool_ts_in
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
- ts->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ONESTEP_P2P);
+ ts->tx_types = BIT(HWTSTAMP_TX_OFF);
- if (is_lan937x(dev))
+ if (!ksz_is_ksz8463(dev))
+ ts->tx_types |= BIT(HWTSTAMP_TX_ONESTEP_P2P);
+
+ if (is_lan937x(dev) || ksz_is_ksz8463(dev))
ts->tx_types |= BIT(HWTSTAMP_TX_ON);
ts->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
- BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
- BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
- BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
+ BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
+ if (!ksz_is_ksz8463(dev)) {
+ ts->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
+ }
ts->phc_index = ptp_clock_index(ptp_data->clock);
@@ -353,6 +358,9 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev,
prt->hwts_tx_en = false;
break;
case HWTSTAMP_TX_ONESTEP_P2P:
+ if (ksz_is_ksz8463(dev))
+ return -ERANGE;
+
prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en = false;
prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true;
prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = false;
@@ -364,14 +372,19 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev,
break;
case HWTSTAMP_TX_ON:
- if (!is_lan937x(dev))
+ if (!is_lan937x(dev) && !ksz_is_ksz8463(dev))
return -ERANGE;
- prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en = true;
- prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true;
- prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = true;
- prt->hwts_tx_en = true;
+ if (ksz_is_ksz8463(dev)) {
+ prt->ptpmsg_irq[KSZ8463_SYNC_MSG].ts_en = true;
+ prt->ptpmsg_irq[KSZ8463_XDREQ_PDRES_MSG].ts_en = true;
+ } else {
+ prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en = true;
+ prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true;
+ prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = true;
+ }
+ prt->hwts_tx_en = true;
ret = ksz_rmw16(dev, regs[PTP_MSG_CONF1], PTP_1STEP, 0);
if (ret)
return ret;
@@ -387,6 +400,8 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev,
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ if (ksz_is_ksz8463(dev))
+ return -ERANGE;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
prt->hwts_rx_en = true;
break;
@@ -397,6 +412,8 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev,
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ if (ksz_is_ksz8463(dev))
+ return -ERANGE;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
prt->hwts_rx_en = true;
break;
@@ -518,6 +535,8 @@ void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
if (!hdr)
return;
+ prt->last_tx_is_pdelayresp = false;
+
ptp_msg_type = ptp_get_msgtype(hdr, type);
switch (ptp_msg_type) {
@@ -528,6 +547,7 @@ void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
case PTP_MSGTYPE_PDELAY_REQ:
break;
case PTP_MSGTYPE_PDELAY_RESP:
+ prt->last_tx_is_pdelayresp = true;
if (prt->tstamp_config.tx_type == HWTSTAMP_TX_ONESTEP_P2P) {
KSZ_SKB_CB(skb)->ptp_type = type;
KSZ_SKB_CB(skb)->update_correction = true;
@@ -972,7 +992,17 @@ void ksz_ptp_clock_unregister(struct dsa_switch *ds)
static int ksz_read_ts(struct ksz_port *port, u16 reg, u32 *ts)
{
- return ksz_read32(port->ksz_dev, reg, ts);
+ u16 ts_reg = reg;
+
+ /**
+ * On KSZ8463 DREQ and DRESP timestamps share one interrupt line
+ * so we have to check the nature of the latest event sent to know
+ * where the timestamp is located
+ */
+ if (ksz_is_ksz8463(port->ksz_dev) && port->last_tx_is_pdelayresp)
+ ts_reg += KSZ8463_DRESP_TS_OFFSET;
+
+ return ksz_read32(port->ksz_dev, ts_reg, ts);
}
static irqreturn_t ksz_ptp_msg_thread_fn(int irq, void *dev_id)
diff --git a/drivers/net/dsa/microchip/ksz_ptp_reg.h b/drivers/net/dsa/microchip/ksz_ptp_reg.h
index e80fb4bd1a0e970ba3570374d3dc82c8e2cc15b4..ac9d0f2b348b0469abbeed0e645fe8ef441d35fb 100644
--- a/drivers/net/dsa/microchip/ksz_ptp_reg.h
+++ b/drivers/net/dsa/microchip/ksz_ptp_reg.h
@@ -125,6 +125,10 @@
#define KSZ8463_REG_PORT_SYNC_TS 0x064C
#define KSZ8463_REG_PORT_DRESP_TS 0x0650
+#define KSZ8463_DRESP_TS_OFFSET (KSZ8463_REG_PORT_DRESP_TS - KSZ8463_REG_PORT_DREQ_TS)
+#define KSZ8463_SYNC_MSG 0
+#define KSZ8463_XDREQ_PDRES_MSG 1
+
#define REG_PTP_PORT_TX_INT_STATUS__2 0x0C14
#define REG_PTP_PORT_TX_INT_ENABLE__2 0x0C16
--
2.52.0
Powered by blists - more mailing lists