From nobody Mon Feb 9 10:27:39 2026 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E4BF333290C for ; Tue, 27 Jan 2026 09:07:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769504823; cv=none; b=d+X1gbfZfxS3jCDLOxUYyBRbMaNLhun8DFbnU0sFwOIToEhFN7ZryGCYf7oKNWVMURwTZ+9+r/F0NzBkAsmoMf16iUMdW+zlt+GCRz2iOhelB7KSEJfl5NaPcgVzI+FgTF4BtQIGyN5BXSOME+vTQqXY051Y8lHrkr3tKn6kZkA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769504823; c=relaxed/simple; bh=/mlP9kI2Or8o2p8fWqvo/LN25FOpFuVX1gQxxlQpdws=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DgHdF/xDlNTpkR81yFxZBBJIJ7/uonM/qLqHUG3tejsmxLY9dZVfl+ph0iRynUI1etesJaeRF7gTyeY8W+4SnaOz5/62FNnfmG3xBu6KvtHPDdzTsprYyOtpFM+wWgqqR8XOfTRZDS+QOrOvb9t5Gb4NBmPDYs3RAl9cOG+o/XY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=pNrVIaij; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="pNrVIaij" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id BFEE01A2A71; Tue, 27 Jan 2026 09:07:00 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 95918606F5; Tue, 27 Jan 2026 09:07:00 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id BD725119A867A; Tue, 27 Jan 2026 10:06:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769504819; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=CP8mvXRQhRbUnoQ95hOGvB8ViUY7+K61hwEjmpRAZp8=; b=pNrVIaiji9uIXXwL1p0sTwNkhY973ZYzYoR4GzV/e62BhcfCXJZbkF2wIcjwcE7rV1FDIv QOJUj8Ab8D3YsW/G7j3A2uaaAEfx796WGjGfFuSloGMSQNnc3knNp+JmWjuPLo1ZJabybT IWko7mp4pQyek2tVDtMFIo3MhFS+FQNVahLn84iHndSQbQZHMAlkcB5ET/bUXEVvtBqCsk Y6RjMB8ccBwqIq/pkRczlr28OvNoVJg3AOu630cy6mMRLCBieEUj9X5WJac0mEvlcPJiTD 3nxNtWbr3/3mkqXBxHwec7uKqJ4WyVZKkvCqr+VLhh7y3YSzrhi28P8cHTjUDQ== From: "Bastien Curutchet (Schneider Electric)" Date: Tue, 27 Jan 2026 10:06:46 +0100 Subject: [PATCH net-next v4 4/8] net: dsa: microchip: Add support for KSZ8463's PTP interrupts Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260127-ksz8463-ptp-v4-4-652e021aae86@bootlin.com> References: <20260127-ksz8463-ptp-v4-0-652e021aae86@bootlin.com> In-Reply-To: <20260127-ksz8463-ptp-v4-0-652e021aae86@bootlin.com> To: Woojung Huh , UNGLinuxDriver@microchip.com, Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Richard Cochran , Simon Horman Cc: Pascal Eberhard , =?utf-8?q?Miqu=C3=A8l_Raynal?= , Thomas Petazzoni , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, "Bastien Curutchet (Schneider Electric)" X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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=C2=B01. Signed-off-by: Bastien Curutchet (Schneider Electric) --- 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/micro= chip/ksz_common.c index 82ec7142a02c432f162e472c831faa010c035123..224be307b3417bf30d62da5c94e= fc6714d914dc6 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; =20 - dsa_switch_for_each_user_port(dp, dev->ds) { - ret =3D ksz_pirq_setup(dev, dp->index); + if (ksz_is_ksz8463(dev)) { + ret =3D ksz8463_ptp_irq_setup(ds); if (ret) - goto port_release; - - if (dev->info->ptp_capable) { - ret =3D ksz_ptp_irq_setup(ds, dp->index); + goto girq_release; + } else { + dsa_switch_for_each_user_port(dp, dev->ds) { + ret =3D ksz_pirq_setup(dev, dp->index); if (ret) - goto pirq_release; + goto port_release; + + if (dev->info->ptp_capable) { + ret =3D 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); =20 return ret; } @@ -3140,11 +3152,14 @@ static void ksz_teardown(struct dsa_switch *ds) ksz_ptp_clock_unregister(ds); =20 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); + } } =20 ksz_irq_free(&dev->girq); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/micro= chip/ksz_common.h index 67a488a3b5787f93f9e2a9266ce04f6611b56bf8..dfbc3d13daca8d7a8b9d3ffe6a7= c1ec9927863f2 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 =20 +#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/microchi= p/ksz_ptp.c index ae46ba41c588c076de2c3b70c7c6702ad85263d5..5daadf62689e6d60ab32e7a5a6c= 1f3fac3024b87 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 =20 #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 =20 static int ksz_ptp_tou_gpio(struct ksz_device *dev) { @@ -1102,6 +1105,7 @@ static void ksz_ptp_msg_irq_free(struct ksz_port *por= t, u8 n) static int ksz_ptp_msg_irq_setup(struct irq_domain *domain, struct ksz_por= t *port, u8 index, int irq) { + static const char * const ksz8463_name[] =3D {"sync-msg", "delay-msg"}; u16 ts_reg[] =3D {REG_PTP_PORT_PDRESP_TS, REG_PTP_PORT_XDELAY_TS, REG_PTP_PORT_SYNC_TS}; static const char * const name[] =3D {"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; =20 ptpmsg_irq->port =3D port; - ptpmsg_irq->ts_reg =3D ops->get_port_addr(port->num, ts_reg[index]); =20 - strscpy(ptpmsg_irq->name, name[index]); + if (ksz_is_ksz8463(port->ksz_dev)) { + ts_reg[0] =3D KSZ8463_REG_PORT_SYNC_TS; + ts_reg[1] =3D KSZ8463_REG_PORT_DREQ_TS; + strscpy(ptpmsg_irq->name, ksz8463_name[index]); + } else { + strscpy(ptpmsg_irq->name, name[index]); + } + + ptpmsg_irq->ts_reg =3D ops->get_port_addr(port->num, ts_reg[index]); =20 return request_threaded_irq(ptpmsg_irq->num, NULL, ksz_ptp_msg_thread_fn, IRQF_ONESHOT, ptpmsg_irq->name, ptpmsg_irq); } =20 +static int ksz8463_ptp_port_irq_setup(struct ksz_irq *ptpirq, struct ksz_p= ort *port, int hw_irq) +{ + int ret; + int i; + + init_completion(&port->tstamp_msg_comp); + + for (i =3D 0; i < 2; i++) { + ret =3D 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 =3D 0; i < 2; i++) + ksz_ptp_msg_irq_free(port, i); +} + +int ksz8463_ptp_irq_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev =3D ds->priv; + struct ksz_port *port1, *port2; + struct ksz_irq *ptpirq; + int ret; + + port1 =3D &dev->ports[0]; + port2 =3D &dev->ports[1]; + ptpirq =3D &port1->ptpirq; + + ptpirq->irq_num =3D irq_find_mapping(dev->girq.domain, KSZ8463_SRC_PTP_IN= T); + if (!ptpirq->irq_num) + return -EINVAL; + + ptpirq->dev =3D dev; + ptpirq->nirqs =3D 4; + ptpirq->reg_mask =3D KSZ8463_PTP_TS_IER; + ptpirq->reg_status =3D KSZ8463_PTP_TS_ISR; + ptpirq->irq0_offset =3D KSZ8463_PTP_INT_START; + snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp-irq"); + + ptpirq->domain =3D irq_domain_create_linear(dev_fwnode(dev->dev), ptpirq-= >nirqs, + &ksz_ptp_irq_domain_ops, ptpirq); + if (!ptpirq->domain) + return -ENOMEM; + + ret =3D request_threaded_irq(ptpirq->irq_num, NULL, ksz_ptp_irq_thread_fn, + IRQF_ONESHOT, ptpirq->name, ptpirq); + if (ret) + goto release_domain; + + ret =3D ksz8463_ptp_port_irq_setup(ptpirq, port1, + KSZ8463_PTP_PORT1_INT_START - KSZ8463_PTP_INT_START); + if (ret) + goto release_irq; + + ret =3D 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 =3D ds->priv; @@ -1181,6 +1276,19 @@ int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) return ret; } =20 +void ksz8463_ptp_irq_free(struct dsa_switch *ds) +{ + struct ksz_device *dev =3D ds->priv; + struct ksz_port *port1 =3D &dev->ports[0]; + struct ksz_port *port2 =3D &dev->ports[1]; + struct ksz_irq *ptpirq =3D &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 =3D ds->priv; diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchi= p/ksz_ptp.h index 3086e519b1b641e9e4126cb6ff43409f6d7f29a5..46494caacc4287b845b8e5c3a68= bcfc7a03bcf9d 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, s= truct 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 *sk= b, 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); =20 @@ -65,6 +67,13 @@ static inline int ksz_ptp_clock_register(struct dsa_swit= ch *ds) =20 static inline void ksz_ptp_clock_unregister(struct dsa_switch *ds) { } =20 +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/micr= ochip/ksz_ptp_reg.h index eab9aecb7fa8a50323de4140695b2004d1beab8c..e80fb4bd1a0e970ba3570374d3d= c82c8e2cc15b4 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 =20 +#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 =20 @@ -131,4 +135,7 @@ #define KSZ_XDREQ_MSG 1 #define KSZ_PDRES_MSG 0 =20 +#define KSZ8463_PTP_TS_ISR 0x68C +#define KSZ8463_PTP_TS_IER 0x68E + #endif --=20 2.52.0