[PATCH net-next v4 4/8] net: dsa: microchip: Add support for KSZ8463's PTP interrupts
From: Bastien Curutchet (Schneider Electric) <hidden>
Date: 2026-01-27 09:07:01
Also in:
lkml
Subsystem:
microchip ksz series ethernet switch driver, networking drivers, networking [dsa], the rest · Maintainers:
Woojung Huh, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Vladimir Oltean, Linus Torvalds
KSZ8463 PTP interrupts aren't handled by the driver. The interrupt layout in KSZ8463 has nothing to do with the other switches: - all the interrupts of all ports are grouped into one status register while others have one interrupt register per port - xdelay_req and pdresp timestamps share one single interrupt bit on the KSZ8463 while each of them has its own interrupt bit on other switches Add KSZ8463-specific IRQ setup()/free() functions to support KSZ8463. Both ports share one IRQ domain held by port n°1. Signed-off-by: Bastien Curutchet (Schneider Electric) <redacted> --- drivers/net/dsa/microchip/ksz_common.c | 49 +++++++++----- drivers/net/dsa/microchip/ksz_common.h | 2 + drivers/net/dsa/microchip/ksz_ptp.c | 112 +++++++++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz_ptp.h | 9 +++ drivers/net/dsa/microchip/ksz_ptp_reg.h | 7 ++ 5 files changed, 160 insertions(+), 19 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 82ec7142a02c432f162e472c831faa010c035123..224be307b3417bf30d62da5c94efc6714d914dc6 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c@@ -3076,15 +3076,21 @@ static int ksz_setup(struct dsa_switch *ds) if (ret) return ret; - dsa_switch_for_each_user_port(dp, dev->ds) { - ret = ksz_pirq_setup(dev, dp->index); + if (ksz_is_ksz8463(dev)) { + ret = ksz8463_ptp_irq_setup(ds); if (ret) - goto port_release; - - if (dev->info->ptp_capable) { - ret = ksz_ptp_irq_setup(ds, dp->index); + goto girq_release; + } else { + dsa_switch_for_each_user_port(dp, dev->ds) { + ret = ksz_pirq_setup(dev, dp->index); if (ret) - goto pirq_release; + goto port_release; + + if (dev->info->ptp_capable) { + ret = ksz_ptp_irq_setup(ds, dp->index); + if (ret) + goto pirq_release; + } } } }
@@ -3119,14 +3125,20 @@ static int ksz_setup(struct dsa_switch *ds) ksz_ptp_clock_unregister(ds); port_release: if (dev->irq > 0) { - dsa_switch_for_each_user_port_continue_reverse(dp, dev->ds) { - if (dev->info->ptp_capable) - ksz_ptp_irq_free(ds, dp->index); + if (ksz_is_ksz8463(dev)) { + ksz8463_ptp_irq_free(ds); + } else { + dsa_switch_for_each_user_port_continue_reverse(dp, dev->ds) { + if (dev->info->ptp_capable) + ksz_ptp_irq_free(ds, dp->index); pirq_release: - ksz_irq_free(&dev->ports[dp->index].pirq); + ksz_irq_free(&dev->ports[dp->index].pirq); + } } - ksz_irq_free(&dev->girq); } +girq_release: + if (dev->irq > 0) + ksz_irq_free(&dev->girq); return ret; }
@@ -3140,11 +3152,14 @@ static void ksz_teardown(struct dsa_switch *ds) ksz_ptp_clock_unregister(ds); if (dev->irq > 0) { - dsa_switch_for_each_user_port(dp, dev->ds) { - if (dev->info->ptp_capable) - ksz_ptp_irq_free(ds, dp->index); - - ksz_irq_free(&dev->ports[dp->index].pirq); + if (ksz_is_ksz8463(dev)) { + ksz8463_ptp_irq_free(ds); + } else { + dsa_switch_for_each_user_port(dp, dev->ds) { + if (dev->info->ptp_capable) + ksz_ptp_irq_free(ds, dp->index); + ksz_irq_free(&dev->ports[dp->index].pirq); + } } ksz_irq_free(&dev->girq);
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 67a488a3b5787f93f9e2a9266ce04f6611b56bf8..dfbc3d13daca8d7a8b9d3ffe6a7c1ec9927863f2 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h@@ -851,6 +851,8 @@ static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port) #define PORT_SRC_PHY_INT 1 #define PORT_SRC_PTP_INT 2 +#define KSZ8463_SRC_PTP_INT 12 + #define KSZ8795_HUGE_PACKET_SIZE 2000 #define KSZ8863_HUGE_PACKET_SIZE 1916 #define KSZ8863_NORMAL_PACKET_SIZE 1536
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index ae46ba41c588c076de2c3b70c7c6702ad85263d5..5daadf62689e6d60ab32e7a5a6c1f3fac3024b87 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c@@ -31,6 +31,9 @@ #define KSZ_PTP_SUBNS_BITS 32 #define KSZ_PTP_INT_START 13 +#define KSZ8463_PTP_PORT1_INT_START 12 +#define KSZ8463_PTP_PORT2_INT_START 14 +#define KSZ8463_PTP_INT_START KSZ8463_PTP_PORT1_INT_START static int ksz_ptp_tou_gpio(struct ksz_device *dev) {
@@ -1102,6 +1105,7 @@ static void ksz_ptp_msg_irq_free(struct ksz_port *port, u8 n) static int ksz_ptp_msg_irq_setup(struct irq_domain *domain, struct ksz_port *port, u8 index, int irq) { + static const char * const ksz8463_name[] = {"sync-msg", "delay-msg"}; u16 ts_reg[] = {REG_PTP_PORT_PDRESP_TS, REG_PTP_PORT_XDELAY_TS, REG_PTP_PORT_SYNC_TS}; static const char * const name[] = {"pdresp-msg", "xdreq-msg",
@@ -1115,15 +1119,106 @@ static int ksz_ptp_msg_irq_setup(struct irq_domain *domain, struct ksz_port *por return -EINVAL; ptpmsg_irq->port = port; - ptpmsg_irq->ts_reg = ops->get_port_addr(port->num, ts_reg[index]); - strscpy(ptpmsg_irq->name, name[index]); + if (ksz_is_ksz8463(port->ksz_dev)) { + ts_reg[0] = KSZ8463_REG_PORT_SYNC_TS; + ts_reg[1] = KSZ8463_REG_PORT_DREQ_TS; + strscpy(ptpmsg_irq->name, ksz8463_name[index]); + } else { + strscpy(ptpmsg_irq->name, name[index]); + } + + ptpmsg_irq->ts_reg = ops->get_port_addr(port->num, ts_reg[index]); return request_threaded_irq(ptpmsg_irq->num, NULL, ksz_ptp_msg_thread_fn, IRQF_ONESHOT, ptpmsg_irq->name, ptpmsg_irq); } +static int ksz8463_ptp_port_irq_setup(struct ksz_irq *ptpirq, struct ksz_port *port, int hw_irq) +{ + int ret; + int i; + + init_completion(&port->tstamp_msg_comp); + + for (i = 0; i < 2; i++) { + ret = ksz_ptp_msg_irq_setup(ptpirq->domain, port, i, hw_irq++); + if (ret) + goto release_msg_irq; + } + + return 0; + +release_msg_irq: + while (i--) + ksz_ptp_msg_irq_free(port, i); + + return ret; +} + +static void ksz8463_ptp_port_irq_teardown(struct ksz_port *port) +{ + int i; + + for (i = 0; i < 2; i++) + ksz_ptp_msg_irq_free(port, i); +} + +int ksz8463_ptp_irq_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *port1, *port2; + struct ksz_irq *ptpirq; + int ret; + + port1 = &dev->ports[0]; + port2 = &dev->ports[1]; + ptpirq = &port1->ptpirq; + + ptpirq->irq_num = irq_find_mapping(dev->girq.domain, KSZ8463_SRC_PTP_INT); + if (!ptpirq->irq_num) + return -EINVAL; + + ptpirq->dev = dev; + ptpirq->nirqs = 4; + ptpirq->reg_mask = KSZ8463_PTP_TS_IER; + ptpirq->reg_status = KSZ8463_PTP_TS_ISR; + ptpirq->irq0_offset = KSZ8463_PTP_INT_START; + snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp-irq"); + + ptpirq->domain = irq_domain_create_linear(dev_fwnode(dev->dev), ptpirq->nirqs, + &ksz_ptp_irq_domain_ops, ptpirq); + if (!ptpirq->domain) + return -ENOMEM; + + ret = request_threaded_irq(ptpirq->irq_num, NULL, ksz_ptp_irq_thread_fn, + IRQF_ONESHOT, ptpirq->name, ptpirq); + if (ret) + goto release_domain; + + ret = ksz8463_ptp_port_irq_setup(ptpirq, port1, + KSZ8463_PTP_PORT1_INT_START - KSZ8463_PTP_INT_START); + if (ret) + goto release_irq; + + ret = ksz8463_ptp_port_irq_setup(ptpirq, port2, + KSZ8463_PTP_PORT2_INT_START - KSZ8463_PTP_INT_START); + if (ret) + goto free_port1; + + return 0; + +free_port1: + ksz8463_ptp_port_irq_teardown(port1); +release_irq: + free_irq(ptpirq->irq_num, ptpirq); +release_domain: + irq_domain_remove(ptpirq->domain); + + return ret; +} + int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) { struct ksz_device *dev = ds->priv;
@@ -1181,6 +1276,19 @@ int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) return ret; } +void ksz8463_ptp_irq_free(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port *port1 = &dev->ports[0]; + struct ksz_port *port2 = &dev->ports[1]; + struct ksz_irq *ptpirq = &port1->ptpirq; + + ksz8463_ptp_port_irq_teardown(port1); + ksz8463_ptp_port_irq_teardown(port2); + free_irq(ptpirq->irq_num, ptpirq); + irq_domain_remove(ptpirq->domain); +} + void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) { struct ksz_device *dev = ds->priv;
diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h
index 3086e519b1b641e9e4126cb6ff43409f6d7f29a5..46494caacc4287b845b8e5c3a68bcfc7a03bcf9d 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.h
+++ b/drivers/net/dsa/microchip/ksz_ptp.h@@ -48,6 +48,8 @@ void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb); void ksz_port_deferred_xmit(struct kthread_work *work); bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb, unsigned int type); +int ksz8463_ptp_irq_setup(struct dsa_switch *ds); +void ksz8463_ptp_irq_free(struct dsa_switch *ds); int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p); void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p);
@@ -65,6 +67,13 @@ static inline int ksz_ptp_clock_register(struct dsa_switch *ds) static inline void ksz_ptp_clock_unregister(struct dsa_switch *ds) { } +static inline int ksz8463_ptp_irq_setup(struct dsa_switch *ds) +{ + return 0; +} + +static inline void ksz8463_ptp_irq_free(struct dsa_switch *ds) {} + static inline int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) { return 0;
diff --git a/drivers/net/dsa/microchip/ksz_ptp_reg.h b/drivers/net/dsa/microchip/ksz_ptp_reg.h
index eab9aecb7fa8a50323de4140695b2004d1beab8c..e80fb4bd1a0e970ba3570374d3dc82c8e2cc15b4 100644
--- a/drivers/net/dsa/microchip/ksz_ptp_reg.h
+++ b/drivers/net/dsa/microchip/ksz_ptp_reg.h@@ -121,6 +121,10 @@ #define REG_PTP_PORT_SYNC_TS 0x0C0C #define REG_PTP_PORT_PDRESP_TS 0x0C10 +#define KSZ8463_REG_PORT_DREQ_TS 0x0648 +#define KSZ8463_REG_PORT_SYNC_TS 0x064C +#define KSZ8463_REG_PORT_DRESP_TS 0x0650 + #define REG_PTP_PORT_TX_INT_STATUS__2 0x0C14 #define REG_PTP_PORT_TX_INT_ENABLE__2 0x0C16
@@ -131,4 +135,7 @@ #define KSZ_XDREQ_MSG 1 #define KSZ_PDRES_MSG 0 +#define KSZ8463_PTP_TS_ISR 0x68C +#define KSZ8463_PTP_TS_IER 0x68E + #endif
--
2.52.0