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) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_common.c | 49 +++++++++-----
drivers/net/dsa/microchip/ksz_common.h | 2 +
drivers/net/dsa/microchip/ksz_ptp.c | 114 +++++++++++++++++++++++++++++++-
drivers/net/dsa/microchip/ksz_ptp.h | 9 +++
drivers/net/dsa/microchip/ksz_ptp_reg.h | 7 ++
5 files changed, 162 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..cafb64785ef4c7eb9c05900a87148e8b7b4678e5 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,108 @@ 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;
+ const struct ksz_dev_ops *ops = dev->dev_ops;
+ struct ksz_port *port1, *port2;
+ struct ksz_irq *ptpirq;
+ int ret;
+ int p;
+
+ 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 = ops->get_port_addr(p, KSZ8463_PTP_TS_IER);
+ ptpirq->reg_status = ops->get_port_addr(p, KSZ8463_PTP_TS_ISR);
+ ptpirq->irq0_offset = KSZ8463_PTP_INT_START;
+ snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp-irq-%d", p);
+
+ 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 +1278,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
Hi Bastien,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 3adff276e751051e77be4df8d29eab1cf0856fbf]
url: https://github.com/intel-lab-lkp/linux/commits/Bastien-Curutchet-Schneider-Electric/net-dsa-microchip-Add-support-for-KSZ8463-global-irq/20260116-000545
base: 3adff276e751051e77be4df8d29eab1cf0856fbf
patch link: https://lore.kernel.org/r/20260115-ksz8463-ptp-v1-4-bcfe2830cf50%40bootlin.com
patch subject: [PATCH net-next 4/8] net: dsa: microchip: Add support for KSZ8463's PTP interrupts
config: loongarch-allmodconfig (https://download.01.org/0day-ci/archive/20260116/202601160729.AzeG6b64-lkp@intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260116/202601160729.AzeG6b64-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/202601160729.AzeG6b64-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/net/dsa/microchip/ksz_ptp.c:1187:40: warning: variable 'p' is uninitialized when used here [-Wuninitialized]
1187 | ptpirq->reg_mask = ops->get_port_addr(p, KSZ8463_PTP_TS_IER);
| ^
drivers/net/dsa/microchip/ksz_ptp.c:1175:7: note: initialize the variable 'p' to silence this warning
1175 | int p;
| ^
| = 0
1 warning generated.
vim +/p +1187 drivers/net/dsa/microchip/ksz_ptp.c
1167
1168 int ksz8463_ptp_irq_setup(struct dsa_switch *ds)
1169 {
1170 struct ksz_device *dev = ds->priv;
1171 const struct ksz_dev_ops *ops = dev->dev_ops;
1172 struct ksz_port *port1, *port2;
1173 struct ksz_irq *ptpirq;
1174 int ret;
1175 int p;
1176
1177 port1 = &dev->ports[0];
1178 port2 = &dev->ports[1];
1179 ptpirq = &port1->ptpirq;
1180
1181 ptpirq->irq_num = irq_find_mapping(dev->girq.domain, KSZ8463_SRC_PTP_INT);
1182 if (!ptpirq->irq_num)
1183 return -EINVAL;
1184
1185 ptpirq->dev = dev;
1186 ptpirq->nirqs = 4;
> 1187 ptpirq->reg_mask = ops->get_port_addr(p, KSZ8463_PTP_TS_IER);
1188 ptpirq->reg_status = ops->get_port_addr(p, KSZ8463_PTP_TS_ISR);
1189 ptpirq->irq0_offset = KSZ8463_PTP_INT_START;
1190 snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp-irq-%d", p);
1191
1192 ptpirq->domain = irq_domain_create_linear(dev_fwnode(dev->dev), ptpirq->nirqs,
1193 &ksz_ptp_irq_domain_ops, ptpirq);
1194 if (!ptpirq->domain)
1195 return -ENOMEM;
1196
1197 ret = request_threaded_irq(ptpirq->irq_num, NULL, ksz_ptp_irq_thread_fn,
1198 IRQF_ONESHOT, ptpirq->name, ptpirq);
1199 if (ret)
1200 goto release_domain;
1201
1202 ret = ksz8463_ptp_port_irq_setup(ptpirq, port1,
1203 KSZ8463_PTP_PORT1_INT_START - KSZ8463_PTP_INT_START);
1204 if (ret)
1205 goto release_irq;
1206
1207 ret = ksz8463_ptp_port_irq_setup(ptpirq, port2,
1208 KSZ8463_PTP_PORT2_INT_START - KSZ8463_PTP_INT_START);
1209 if (ret)
1210 goto free_port1;
1211
1212 return 0;
1213
1214 free_port1:
1215 ksz8463_ptp_port_irq_teardown(port1);
1216 release_irq:
1217 free_irq(ptpirq->irq_num, ptpirq);
1218 release_domain:
1219 irq_domain_remove(ptpirq->domain);
1220
1221 return ret;
1222 }
1223
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.