* [PATCH net-next v2 01/10] net: dsa: microchip: add the number of pins to chip infos
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-05 1:55 ` netdev-bot+sashiko
2026-09-02 9:57 ` [PATCH net-next v2 02/10] net: dsa: microchip: add the number of periodic signals " Bastien Curutchet (Schneider Electric)
` (8 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The number of periodic output pins available is hardcoded to 2 while
KSZ8463 has 12 pins that can be used as periodic outputs.
Add an n_pin attribute to the struct ksz_chip_data to make this setting
configurable.
Set it to 2 for all the PTP-capable switches.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_common.c | 10 ++++++++++
drivers/net/dsa/microchip/ksz_common.h | 1 +
drivers/net/dsa/microchip/ksz_ptp.c | 4 ++--
3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 1a9d6f83a023..d01fba253af5 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -1194,6 +1194,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.ptp_capable = true,
.wr_table = &ksz8563_register_set,
.rd_table = &ksz8563_register_set,
+ .n_pins = 2,
},
[KSZ8795] = {
@@ -1414,6 +1415,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.sgmii_port = 7,
.wr_table = &ksz9477_register_set,
.rd_table = &ksz9477_register_set,
+ .n_pins = 2,
},
[KSZ9896] = {
@@ -1544,6 +1546,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.internal_phy = {true, true, false},
.gbit_capable = {true, true, true},
.ptp_capable = true,
+ .n_pins = 2,
},
[KSZ8567] = {
@@ -1581,6 +1584,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.gbit_capable = {false, false, false, false, false,
true, true},
.ptp_capable = true,
+ .n_pins = 2,
},
[KSZ9567] = {
@@ -1615,6 +1619,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
true, false, false},
.gbit_capable = {true, true, true, true, true, true, true},
.ptp_capable = true,
+ .n_pins = 2,
},
[LAN9370] = {
@@ -1646,6 +1651,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.supports_rgmii = {false, false, false, false, true},
.internal_phy = {true, true, true, true, false},
.ptp_capable = true,
+ .n_pins = 2,
},
[LAN9371] = {
@@ -1677,6 +1683,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.supports_rgmii = {false, false, false, false, true, true},
.internal_phy = {true, true, true, true, false, false},
.ptp_capable = true,
+ .n_pins = 2,
},
[LAN9372] = {
@@ -1712,6 +1719,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.internal_phy = {true, true, true, true,
false, false, true, true},
.ptp_capable = true,
+ .n_pins = 2,
},
[LAN9373] = {
@@ -1747,6 +1755,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.internal_phy = {true, true, true, false,
false, false, true, true},
.ptp_capable = true,
+ .n_pins = 2,
},
[LAN9374] = {
@@ -1782,6 +1791,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.internal_phy = {true, true, true, true,
false, false, true, true},
.ptp_capable = true,
+ .n_pins = 2,
},
[LAN9646] = {
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index cbe98494578c..c678fc6597dc 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -139,6 +139,7 @@ struct ksz_chip_data {
u8 sgmii_port;
const struct regmap_access_table *wr_table;
const struct regmap_access_table *rd_table;
+ const u8 n_pins;
};
struct ksz_irq {
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index 39cc70d65900..c92936bf78d3 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -1050,14 +1050,14 @@ int ksz_ptp_clock_register(struct dsa_switch *ds)
ptp_data->caps.do_aux_work = ksz_ptp_do_aux_work;
ptp_data->caps.enable = ksz_ptp_enable;
ptp_data->caps.verify = ksz_ptp_verify_pin;
- ptp_data->caps.n_pins = KSZ_PTP_N_GPIO;
+ ptp_data->caps.n_pins = dev->info->n_pins;
ptp_data->caps.n_per_out = 3;
ret = ksz_ptp_start_clock(dev);
if (ret)
return ret;
- for (i = 0; i < KSZ_PTP_N_GPIO; i++) {
+ for (i = 0; i < dev->info->n_pins; i++) {
struct ptp_pin_desc *ptp_pin = &ptp_data->pin_config[i];
snprintf(ptp_pin->name,
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH net-next v2 01/10] net: dsa: microchip: add the number of pins to chip infos
2026-09-02 9:57 ` [PATCH net-next v2 01/10] net: dsa: microchip: add the number of pins to chip infos Bastien Curutchet (Schneider Electric)
@ 2026-09-05 1:55 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-09-05 1:55 UTC (permalink / raw)
To: bastien.curutchet
Cc: woojung.huh, UNGLinuxDriver, andrew, olteanv, davem, edumazet,
kuba, pabeni, richardcochran, pascal.eberhard, miquel.raynal,
thomas.petazzoni, netdev, linux-kernel
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 1 · Low: 1
- [Medium] KSZ8463 loses its two PTP pins in this commit:
`ksz_ptp_clock_register()` (drivers/net/dsa/microchip/ksz_ptp.c:1053)…
- [Low] Decoupling of `ptp_data->caps.n_pins` / pin_config loop bound
from the fixed-size array `struct ptp_pin_desc…
--
net: dsa: microchip: add the number of pins to chip infos
This patch adds an n_pins field to struct ksz_chip_data and uses it in
ksz_ptp_clock_register() instead of the hardcoded KSZ_PTP_N_GPIO, both for
ptp_data->caps.n_pins and for the pin_config[] initialization loop. The
new field is set to 2 for the switches marked ptp_capable.
> diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
> index 1a9d6f83a0232..d01fba253af57 100644
> --- a/drivers/net/dsa/microchip/ksz_common.c
> +++ b/drivers/net/dsa/microchip/ksz_common.c
> @@ -1194,6 +1194,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
> .ptp_capable = true,
> .wr_table = &ksz8563_register_set,
> .rd_table = &ksz8563_register_set,
> + .n_pins = 2,
> },
>
> [KSZ8795] = {
[ ... ]
> diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
> index cbe98494578c3..c678fc6597dc4 100644
> --- a/drivers/net/dsa/microchip/ksz_common.h
> +++ b/drivers/net/dsa/microchip/ksz_common.h
> @@ -139,6 +139,7 @@ struct ksz_chip_data {
> u8 sgmii_port;
> const struct regmap_access_table *wr_table;
> const struct regmap_access_table *rd_table;
> + const u8 n_pins;
> };
[Severity: Low]
This isn't a bug today, but the new n_pins field has nothing tying it to
the capacity of the array it indexes. ksz_ptp.h still declares:
drivers/net/dsa/microchip/ksz_ptp.h:
#define KSZ_PTP_N_GPIO 2
...
struct ptp_pin_desc pin_config[KSZ_PTP_N_GPIO];
/* Serializes all operations on the PTP hardware clock */
struct mutex lock;
spinlock_t clock_lock;
I checked all ten entries that get .n_pins here and they are all 2, and
the later commit that raises KSZ8463 to 12 bumps KSZ_PTP_N_GPIO to 12 in
the same patch, so no entry ever exceeds the array. Would it be worth
adding a static_assert() or a
BUILD_BUG_ON(n_pins <= ARRAY_SIZE(ptp_data->pin_config)) so a future chip
entry with a larger n_pins cannot walk past pin_config[] into lock and
clock_lock?
Also, is the const qualifier on n_pins intentional? The other scalar
members of struct ksz_chip_data (u8 sgmii_port, port_cnt, ...) are plain.
> diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
> index 39cc70d65900b..c92936bf78d3d 100644
> --- a/drivers/net/dsa/microchip/ksz_ptp.c
> +++ b/drivers/net/dsa/microchip/ksz_ptp.c
> @@ -1050,14 +1050,14 @@ int ksz_ptp_clock_register(struct dsa_switch *ds)
> ptp_data->caps.do_aux_work = ksz_ptp_do_aux_work;
> ptp_data->caps.enable = ksz_ptp_enable;
> ptp_data->caps.verify = ksz_ptp_verify_pin;
> - ptp_data->caps.n_pins = KSZ_PTP_N_GPIO;
> + ptp_data->caps.n_pins = dev->info->n_pins;
> ptp_data->caps.n_per_out = 3;
>
> ret = ksz_ptp_start_clock(dev);
> if (ret)
> return ret;
>
> - for (i = 0; i < KSZ_PTP_N_GPIO; i++) {
> + for (i = 0; i < dev->info->n_pins; i++) {
> struct ptp_pin_desc *ptp_pin = &ptp_data->pin_config[i];
>
> snprintf(ptp_pin->name,
[Severity: Medium]
Does this leave KSZ8463 with zero PTP pins at this commit?
The commit message says:
"Set it to 2 for all the PTP-capable switches."
The .n_pins = 2 initializers are added only to the ten entries that carry
.ptp_capable = true (KSZ8563, KSZ9477, KSZ9563, KSZ8567, KSZ9567 and
LAN9370/71/72/73/74). The [KSZ8463] entry in ksz_switch_chips[] does not
have .ptp_capable and does not get .n_pins, so dev->info->n_pins is 0 for
it.
KSZ8463 still reaches this function though, since ksz8463_setup() gates
the registration on the interrupt only:
drivers/net/dsa/microchip/ksz8.c:ksz8463_setup() {
if (dev->irq > 0) {
...
ret = ksz8463_ptp_irq_setup(ds);
...
ret = ksz_ptp_clock_register(ds);
With caps.n_pins == 0 and the loop body never executed, no pin descriptor
is initialized, PTP_PIN_GETFUNC/PTP_PIN_SETFUNC reject every index, and
drivers/net/dsa/microchip/ksz_ptp.c:ksz_ptp_enable_perout() {
pin = ptp_find_pin(ptp_data->clock, PTP_PF_PEROUT, request->index);
if (pin < 0)
return -EINVAL;
can never find a pin, so every PTP_PEROUT_REQUEST on a KSZ8463 with a
working interrupt returns -EINVAL, where two pins were advertised before
this patch.
The end of the series is fine: the later commit "net: dsa: microchip: add
periodic output support for the KSZ8463" adds .n_pins = 12 (and
.n_per_out = 12) to the [KSZ8463] entry. Could the .n_pins value for
KSZ8463 be set in this patch instead, so that the intermediate commits of
the series do not regress periodic output on that chip?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260902-ksz-perout-v2-0-6f277fcc9e68%40bootlin.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net-next v2 02/10] net: dsa: microchip: add the number of periodic signals to chip infos
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 01/10] net: dsa: microchip: add the number of pins to chip infos Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-05 1:55 ` netdev-bot+sashiko
2026-09-02 9:57 ` [PATCH net-next v2 03/10] net: dsa: microchip: use dynamic mask to check pulse width validity Bastien Curutchet (Schneider Electric)
` (7 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The number of periodic signals available is hardcoded to 3 while
KSZ8463 can produce 12 different periodic signals.
Add an n_per_out attribute to the struct ksz_chip_data to make this
setting configurable.
Set it to 3 for all the PTP-capable switches.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_common.c | 10 ++++++++++
drivers/net/dsa/microchip/ksz_common.h | 1 +
drivers/net/dsa/microchip/ksz_ptp.c | 2 +-
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index d01fba253af5..041bb4f96365 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -1195,6 +1195,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.wr_table = &ksz8563_register_set,
.rd_table = &ksz8563_register_set,
.n_pins = 2,
+ .n_per_out = 3,
},
[KSZ8795] = {
@@ -1416,6 +1417,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.wr_table = &ksz9477_register_set,
.rd_table = &ksz9477_register_set,
.n_pins = 2,
+ .n_per_out = 3,
},
[KSZ9896] = {
@@ -1547,6 +1549,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.gbit_capable = {true, true, true},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[KSZ8567] = {
@@ -1585,6 +1588,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
true, true},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[KSZ9567] = {
@@ -1620,6 +1624,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.gbit_capable = {true, true, true, true, true, true, true},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[LAN9370] = {
@@ -1652,6 +1657,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.internal_phy = {true, true, true, true, false},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[LAN9371] = {
@@ -1684,6 +1690,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.internal_phy = {true, true, true, true, false, false},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[LAN9372] = {
@@ -1720,6 +1727,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
false, false, true, true},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[LAN9373] = {
@@ -1756,6 +1764,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
false, false, true, true},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[LAN9374] = {
@@ -1792,6 +1801,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
false, false, true, true},
.ptp_capable = true,
.n_pins = 2,
+ .n_per_out = 3,
},
[LAN9646] = {
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index c678fc6597dc..1155b39350c2 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -140,6 +140,7 @@ struct ksz_chip_data {
const struct regmap_access_table *wr_table;
const struct regmap_access_table *rd_table;
const u8 n_pins;
+ const u8 n_per_out;
};
struct ksz_irq {
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index c92936bf78d3..f80015250e5a 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -1051,7 +1051,7 @@ int ksz_ptp_clock_register(struct dsa_switch *ds)
ptp_data->caps.enable = ksz_ptp_enable;
ptp_data->caps.verify = ksz_ptp_verify_pin;
ptp_data->caps.n_pins = dev->info->n_pins;
- ptp_data->caps.n_per_out = 3;
+ ptp_data->caps.n_per_out = dev->info->n_per_out;
ret = ksz_ptp_start_clock(dev);
if (ret)
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH net-next v2 02/10] net: dsa: microchip: add the number of periodic signals to chip infos
2026-09-02 9:57 ` [PATCH net-next v2 02/10] net: dsa: microchip: add the number of periodic signals " Bastien Curutchet (Schneider Electric)
@ 2026-09-05 1:55 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-09-05 1:55 UTC (permalink / raw)
To: bastien.curutchet
Cc: woojung.huh, UNGLinuxDriver, andrew, olteanv, davem, edumazet,
kuba, pabeni, richardcochran, pascal.eberhard, miquel.raynal,
thomas.petazzoni, netdev, linux-kernel
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 0 (1) · Low: 1 (1)
- [Low] Incomplete conversion for KSZ8463: `ksz_ptp_clock_register()`
(drivers/net/dsa/microchip/ksz_ptp.c:1054) now takes the advertised…
Pre-existing issues:
- [Medium] The driver advertises `n_per_out` periodic-output channels (3
for every PTP-capable chip, now sourced from chip data) but keeps only…
- [Low] In `ksz_ptp_tou_reset()`
(drivers/net/dsa/microchip/ksz_ptp.c:66-88, the TRIG_RESET write at…
--
net: dsa: microchip: add the number of periodic signals to chip infos
This adds an n_per_out field to struct ksz_chip_data and uses it in
ksz_ptp_clock_register() instead of the hardcoded value 3. The field is
populated with 3 for every chip entry carrying .ptp_capable = true.
> diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
> index d01fba253af57..041bb4f963659 100644
> --- a/drivers/net/dsa/microchip/ksz_common.c
> +++ b/drivers/net/dsa/microchip/ksz_common.c
> @@ -1195,6 +1195,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
> .wr_table = &ksz8563_register_set,
> .rd_table = &ksz8563_register_set,
> .n_pins = 2,
> + .n_per_out = 3,
> },
>
> [KSZ8795] = {
[Severity: Low]
Should the KSZ8463 entry get an n_per_out value too?
The commit message says "Set it to 3 for all the PTP-capable switches", which
matches the .ptp_capable chip-data flag, but KSZ8463 registers a PTP clock
without that flag:
drivers/net/dsa/microchip/ksz8.c:ksz8463_setup() {
...
if (dev->irq > 0) {
...
ret = ksz_ptp_clock_register(ds);
if (ret) {
dev_err(dev->dev, "Failed to register PTP clock: %d\n", ret);
...
}
The [KSZ8463] initializer in ksz_switch_chips[] sets neither .n_pins (added
by the preceding patch) nor .n_per_out, so both stay 0 in this static const
table. Does that mean the KSZ8463 clock now advertises n_per_out = 0
(previously 3) and n_pins = 0 (previously KSZ_PTP_N_GPIO), making the PTP
core reject every PTP_PEROUT_REQUEST with -EINVAL and leaving
ptp_find_pin() with no descriptors?
No working output is actually lost at this commit, since the only perout
implementation here is ksz_ptp_enable_perout(), which programs ksz9477-only
registers, and the later patch "net: dsa: microchip: add periodic output
support for the KSZ8463" does set .n_pins = 12 and .n_per_out = 12 on that
entry. Would it be cleaner to set the KSZ8463 values in this patch so no
intermediate commit advertises zero channels or pins?
[ ... remaining ksz_common.c chip entries and the ksz_common.h hunk snipped ... ]
> diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
> index c92936bf78d3d..f80015250e5ab 100644
> --- a/drivers/net/dsa/microchip/ksz_ptp.c
> +++ b/drivers/net/dsa/microchip/ksz_ptp.c
> @@ -1051,7 +1051,7 @@ int ksz_ptp_clock_register(struct dsa_switch *ds)
> ptp_data->caps.enable = ksz_ptp_enable;
> ptp_data->caps.verify = ksz_ptp_verify_pin;
> ptp_data->caps.n_pins = dev->info->n_pins;
> - ptp_data->caps.n_per_out = 3;
> + ptp_data->caps.n_per_out = dev->info->n_per_out;
[Severity: Medium]
This isn't a bug introduced by this patch, but now that the advertised
number of periodic outputs becomes per-chip data, is the driver's shadow
state able to describe more than one trigger unit?
ksz_ptp_enable_perout() programs the unit selected by the request index:
data32 = FIELD_PREP(PTP_GPIO_INDEX, pin) |
FIELD_PREP(PTP_TOU_INDEX, request->index);
but only one tou_mode, one perout_period and one perout_target_time_first
are stored, and the re-arm path hardcodes unit 0:
drivers/net/dsa/microchip/ksz_ptp.c:ksz_ptp_restart_perout() {
...
request.period.nsec = ptp_data->perout_period.tv_nsec;
request.index = 0;
request.flags = 0;
return ksz_ptp_enable_perout(dev, &request, 1);
}
If userspace arms channel 1 or 2 (the -EBUSY guard only compares tou_mode,
never the unit index), does a later settime/adjtime leave hardware unit 1
or 2 still TRIG_ENABLE'd with a target time in the old timebase while the
driver re-arms idle unit 0?
There is a second effect on the same path: ksz_ptp_enable_perout() starts
with ptp_find_pin(ptp_data->clock, PTP_PF_PEROUT, request->index). With a
pin assigned only to channel 1, the lookup for index 0 fails, so
ksz_ptp_settime()/ksz_ptp_adjtime() return -EINVAL after the RTC has
already been written and before ptp_data->clock_time is refreshed under
clock_lock. Does that leave the software clock shadow stale and skew
timestamp reconstruction?
This is still the case at the end of the series, where KSZ8463 additionally
advertises 12 channels against the same single-unit shadow state.
[Severity: Low]
This is a pre-existing issue and the patch does not touch this function,
but the TRIG_RESET write result in ksz_ptp_tou_reset() is discarded:
drivers/net/dsa/microchip/ksz_ptp.c:ksz_ptp_tou_reset() {
/* Reset trigger unit (clears TRIGGER_EN, but not GPIOSTATx) */
ret = ksz_rmw32(dev, REG_PTP_CTRL_STAT__4, TRIG_RESET, TRIG_RESET);
data = FIELD_PREP(TRIG_DONE_M, BIT(unit));
ret = ksz_write32(dev, REG_PTP_TRIG_STATUS__4, data);
if (ret)
return ret;
...
}
ret is overwritten before it is tested. If the read-modify-write fails but
the following write succeeds, can the helper return 0 with the trigger unit
never put into reset, so ksz_ptp_enable_perout() rewrites TRIG_CTRL, cycle
width, cycle count, pulse width and target time on a still-enabled unit?
On the !on path, tou_mode is also set to KSZ_PTP_TOU_IDLE while the unit may
remain armed.
This is unchanged at the end of the series.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260902-ksz-perout-v2-0-6f277fcc9e68%40bootlin.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net-next v2 03/10] net: dsa: microchip: use dynamic mask to check pulse width validity
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 01/10] net: dsa: microchip: add the number of pins to chip infos Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 02/10] net: dsa: microchip: add the number of periodic signals " Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 04/10] net: dsa: microchip: extract PTP callbacks configuration from PTP registration Bastien Curutchet (Schneider Electric)
` (6 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The pulse width validity is checked against an hardcoded mask. KSZ8463
uses a smaller register than other switches so this check won't work for
it.
Move the mask as a ksz_ptp_tou_pulse_verify()'s input to allow changing
it for KSZ8463 case.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_ptp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index f80015250e5a..7bf83e0b5918 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -86,7 +86,7 @@ static int ksz_ptp_tou_reset(struct ksz_device *dev, u8 unit)
0);
}
-static int ksz_ptp_tou_pulse_verify(u64 pulse_ns)
+static int ksz_ptp_tou_pulse_verify(u64 pulse_ns, u32 mask)
{
u32 data;
@@ -94,7 +94,7 @@ static int ksz_ptp_tou_pulse_verify(u64 pulse_ns)
return -EINVAL;
data = (pulse_ns / 8);
- if (!FIELD_FIT(TRIG_PULSE_WIDTH_M, data))
+ if ((mask & data) != data)
return -ERANGE;
return 0;
@@ -245,7 +245,7 @@ static int ksz_ptp_enable_perout(struct ksz_device *dev,
KSZ_MAX_PULSE_WIDTH);
}
- ret = ksz_ptp_tou_pulse_verify(pulse_width_ns);
+ ret = ksz_ptp_tou_pulse_verify(pulse_width_ns, TRIG_PULSE_WIDTH_M);
if (ret)
return ret;
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next v2 04/10] net: dsa: microchip: extract PTP callbacks configuration from PTP registration
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
` (2 preceding siblings ...)
2026-09-02 9:57 ` [PATCH net-next v2 03/10] net: dsa: microchip: use dynamic mask to check pulse width validity Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 05/10] net: dsa: microchip: extract ptp_get_pin Bastien Curutchet (Schneider Electric)
` (5 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
KSZ8463 also has periodic output capabilities but the way its outputs
are driven differs from the other switches. It will need its own set of
PTP callbacks to implements this behaviour.
Extract the PTP callbacks configuration in a dedicated function to be
called before the PTP registration to ease the use of others callbacks
when needed.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz8.c | 2 ++
drivers/net/dsa/microchip/ksz9477.c | 1 +
drivers/net/dsa/microchip/ksz_ptp.c | 20 ++++++++++++++------
drivers/net/dsa/microchip/ksz_ptp.h | 2 ++
drivers/net/dsa/microchip/lan937x_main.c | 1 +
5 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
index 941ae9f66f70..f2a23e2e474a 100644
--- a/drivers/net/dsa/microchip/ksz8.c
+++ b/drivers/net/dsa/microchip/ksz8.c
@@ -2478,6 +2478,7 @@ static int ksz8463_setup(struct dsa_switch *ds)
if (ret)
goto free_girq;
+ ksz_ptp_set_caps(ds);
ret = ksz_ptp_clock_register(ds);
if (ret) {
dev_err(dev->dev, "Failed to register PTP clock: %d\n",
@@ -2775,6 +2776,7 @@ static int ksz8_setup(struct dsa_switch *ds)
}
if (dev->info->ptp_capable) {
+ ksz_ptp_set_caps(ds);
ret = ksz_ptp_clock_register(ds);
if (ret) {
dev_err(dev->dev, "Failed to register PTP clock: %d\n",
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index 3ee995545c57..72528a53b67d 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -1781,6 +1781,7 @@ static int ksz9477_setup(struct dsa_switch *ds)
}
if (dev->info->ptp_capable) {
+ ksz_ptp_set_caps(ds);
ret = ksz_ptp_clock_register(ds);
if (ret) {
dev_err(dev->dev, "Failed to register PTP clock: %d\n",
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index 7bf83e0b5918..ea22601f6b26 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -1028,17 +1028,12 @@ static int ksz_ptp_start_clock(struct ksz_device *dev)
return 0;
}
-int ksz_ptp_clock_register(struct dsa_switch *ds)
+void ksz_ptp_set_caps(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
- const u16 *regs = dev->info->regs;
struct ksz_ptp_data *ptp_data;
- int ret;
- u8 i;
ptp_data = &dev->ptp_data;
- mutex_init(&ptp_data->lock);
- spin_lock_init(&ptp_data->clock_lock);
ptp_data->caps.owner = THIS_MODULE;
snprintf(ptp_data->caps.name, 16, "Microchip Clock");
@@ -1052,6 +1047,19 @@ int ksz_ptp_clock_register(struct dsa_switch *ds)
ptp_data->caps.verify = ksz_ptp_verify_pin;
ptp_data->caps.n_pins = dev->info->n_pins;
ptp_data->caps.n_per_out = dev->info->n_per_out;
+}
+
+int ksz_ptp_clock_register(struct dsa_switch *ds)
+{
+ struct ksz_device *dev = ds->priv;
+ const u16 *regs = dev->info->regs;
+ struct ksz_ptp_data *ptp_data;
+ int ret;
+ u8 i;
+
+ ptp_data = &dev->ptp_data;
+ mutex_init(&ptp_data->lock);
+ spin_lock_init(&ptp_data->clock_lock);
ret = ksz_ptp_start_clock(dev);
if (ret)
diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h
index 7067ec9bd1e6..89716b31596b 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.h
+++ b/drivers/net/dsa/microchip/ksz_ptp.h
@@ -33,6 +33,7 @@ struct ksz_ptp_data {
struct timespec64 perout_period;
};
+void ksz_ptp_set_caps(struct dsa_switch *ds);
int ksz_ptp_clock_register(struct dsa_switch *ds);
void ksz_ptp_clock_unregister(struct dsa_switch *ds);
@@ -65,6 +66,7 @@ struct ksz_ptp_data {
struct mutex lock;
};
+static inline void ksz_ptp_set_caps(struct dsa_switch *ds) { }
static inline int ksz_ptp_clock_register(struct dsa_switch *ds)
{
return 0;
diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c
index 86ce3a86705f..3a209122fc7d 100644
--- a/drivers/net/dsa/microchip/lan937x_main.c
+++ b/drivers/net/dsa/microchip/lan937x_main.c
@@ -867,6 +867,7 @@ static int lan937x_setup(struct dsa_switch *ds)
}
}
+ ksz_ptp_set_caps(ds);
ret = ksz_ptp_clock_register(ds);
if (ret) {
dev_err(dev->dev, "Failed to register PTP clock: %d\n",
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next v2 05/10] net: dsa: microchip: extract ptp_get_pin
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
` (3 preceding siblings ...)
2026-09-02 9:57 ` [PATCH net-next v2 04/10] net: dsa: microchip: extract PTP callbacks configuration from PTP registration Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 06/10] net: dsa: microchip: extract compute_width Bastien Curutchet (Schneider Electric)
` (4 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The KSZ8463 supports periodic outputs but doesn't handle them in the same
way as the other KSZ switches. To add proper support for the KSZ8463, a
dedicated ksz8463_ptp_enable_perout() function needs to be created. This
function will use the same algorithm to select the output pin as the
common ksz_ptp_enable_perout() function.
Extract the pin selection algorithm into a dedicated function so it can
be used later by the KSZ8463 support.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_ptp.c | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index ea22601f6b26..f97ea9d69ebc 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -183,17 +183,11 @@ static int ksz_ptp_configure_perout(struct ksz_device *dev,
return 0;
}
-static int ksz_ptp_enable_perout(struct ksz_device *dev,
- struct ptp_perout_request const *request,
- int on)
+static int ksz_ptp_get_pin(struct ksz_device *dev,
+ struct ptp_perout_request const *request)
{
struct ksz_ptp_data *ptp_data = &dev->ptp_data;
- u64 req_pulse_width_ns;
- u64 cycle_width_ns;
- u64 pulse_width_ns;
- int pin = 0;
- u32 data32;
- int ret;
+ int pin;
if (request->flags & ~PTP_PEROUT_DUTY_CYCLE)
return -EOPNOTSUPP;
@@ -206,6 +200,25 @@ static int ksz_ptp_enable_perout(struct ksz_device *dev,
if (pin < 0)
return -EINVAL;
+ return pin;
+}
+
+static int ksz_ptp_enable_perout(struct ksz_device *dev,
+ struct ptp_perout_request const *request,
+ int on)
+{
+ struct ksz_ptp_data *ptp_data = &dev->ptp_data;
+ u64 req_pulse_width_ns;
+ u64 cycle_width_ns;
+ u64 pulse_width_ns;
+ int pin = 0;
+ u32 data32;
+ int ret;
+
+ pin = ksz_ptp_get_pin(dev, request);
+ if (pin < 0)
+ return pin;
+
data32 = FIELD_PREP(PTP_GPIO_INDEX, pin) |
FIELD_PREP(PTP_TOU_INDEX, request->index);
ret = ksz_rmw32(dev, REG_PTP_UNIT_INDEX__4,
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next v2 06/10] net: dsa: microchip: extract compute_width
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
` (4 preceding siblings ...)
2026-09-02 9:57 ` [PATCH net-next v2 05/10] net: dsa: microchip: extract ptp_get_pin Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 07/10] net: dsa: microchip: extract prepare reset Bastien Curutchet (Schneider Electric)
` (3 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The KSZ8463 supports periodic outputs but doesn't handle them in the same
way as the other KSZ switches. To add proper support for the KSZ8463, a
dedicated ksz8463_ptp_enable_perout() function needs to be created. This
function will use the same algorithm to compute the periodic cycles as
the common ksz_ptp_enable_perout() function.
Extract these algorithms into dedicated functions so they can be used
later by the KSZ8463 support.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_ptp.c | 67 ++++++++++++++++++++++++-------------
1 file changed, 43 insertions(+), 24 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index f97ea9d69ebc..2f141df65eb0 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -203,12 +203,49 @@ static int ksz_ptp_get_pin(struct ksz_device *dev,
return pin;
}
+static int ksz_ptp_compute_perout_cycle(struct ksz_device *dev,
+ struct ptp_perout_request const *request,
+ u64 *cycle_width_ns)
+{
+ struct ksz_ptp_data *ptp_data = &dev->ptp_data;
+
+ ptp_data->perout_target_time_first.tv_sec = request->start.sec;
+ ptp_data->perout_target_time_first.tv_nsec = request->start.nsec;
+
+ ptp_data->perout_period.tv_sec = request->period.sec;
+ ptp_data->perout_period.tv_nsec = request->period.nsec;
+
+ *cycle_width_ns = timespec64_to_ns(&ptp_data->perout_period);
+ if ((*cycle_width_ns & TRIG_CYCLE_WIDTH_M) != *cycle_width_ns) {
+ *cycle_width_ns = 0;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u64 ksz_ptp_compute_perout_pulse(struct ksz_device *dev,
+ struct ptp_perout_request const *request,
+ u64 max_pulse_width)
+{
+ u64 req_pulse_width_ns;
+
+ if (request->flags & PTP_PEROUT_DUTY_CYCLE)
+ return request->on.sec * NSEC_PER_SEC + request->on.nsec;
+
+ /* Use a duty cycle of 50%. Maximum pulse width supported by the
+ * hardware is a little bit more than 125 ms.
+ */
+ req_pulse_width_ns = (request->period.sec * NSEC_PER_SEC +
+ request->period.nsec) / 2;
+ return min_t(u64, req_pulse_width_ns, max_pulse_width);
+}
+
static int ksz_ptp_enable_perout(struct ksz_device *dev,
struct ptp_perout_request const *request,
int on)
{
struct ksz_ptp_data *ptp_data = &dev->ptp_data;
- u64 req_pulse_width_ns;
u64 cycle_width_ns;
u64 pulse_width_ns;
int pin = 0;
@@ -234,29 +271,11 @@ static int ksz_ptp_enable_perout(struct ksz_device *dev,
ptp_data->tou_mode = KSZ_PTP_TOU_IDLE;
return 0;
}
-
- ptp_data->perout_target_time_first.tv_sec = request->start.sec;
- ptp_data->perout_target_time_first.tv_nsec = request->start.nsec;
-
- ptp_data->perout_period.tv_sec = request->period.sec;
- ptp_data->perout_period.tv_nsec = request->period.nsec;
-
- cycle_width_ns = timespec64_to_ns(&ptp_data->perout_period);
- if ((cycle_width_ns & TRIG_CYCLE_WIDTH_M) != cycle_width_ns)
- return -EINVAL;
-
- if (request->flags & PTP_PEROUT_DUTY_CYCLE) {
- pulse_width_ns = request->on.sec * NSEC_PER_SEC +
- request->on.nsec;
- } else {
- /* Use a duty cycle of 50%. Maximum pulse width supported by the
- * hardware is a little bit more than 125 ms.
- */
- req_pulse_width_ns = (request->period.sec * NSEC_PER_SEC +
- request->period.nsec) / 2;
- pulse_width_ns = min_t(u64, req_pulse_width_ns,
- KSZ_MAX_PULSE_WIDTH);
- }
+ ret = ksz_ptp_compute_perout_cycle(dev, request, &cycle_width_ns);
+ if (ret)
+ return ret;
+ pulse_width_ns = ksz_ptp_compute_perout_pulse(dev, request,
+ KSZ_MAX_PULSE_WIDTH);
ret = ksz_ptp_tou_pulse_verify(pulse_width_ns, TRIG_PULSE_WIDTH_M);
if (ret)
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next v2 07/10] net: dsa: microchip: extract prepare reset
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
` (5 preceding siblings ...)
2026-09-02 9:57 ` [PATCH net-next v2 06/10] net: dsa: microchip: extract compute_width Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 08/10] net: dsa: microchip: extract time update Bastien Curutchet (Schneider Electric)
` (2 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The KSZ8463 supports periodic outputs but doesn't handle them in the same
way as the other KSZ switches. To add proper support for the KSZ8463, a
dedicated ksz8463_ptp_restart_perout() function needs to be created. This
function will use the same request initialization as the common
ksz_ptp_restart_perout() function.
Extract the inialization into a dedicated function so it can be used
later by the KSZ8463 support.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_ptp.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index 2f141df65eb0..e262bc7448f2 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -788,11 +788,11 @@ static int ksz_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
return ret;
}
-static int ksz_ptp_restart_perout(struct ksz_device *dev)
+static int ksz_ptp_prepare_restart_perout(struct ksz_device *dev,
+ struct ptp_perout_request *request)
{
struct ksz_ptp_data *ptp_data = &dev->ptp_data;
s64 now_ns, first_ns, period_ns, next_ns;
- struct ptp_perout_request request;
struct timespec64 next;
struct timespec64 now;
unsigned int count;
@@ -823,12 +823,24 @@ static int ksz_ptp_restart_perout(struct ksz_device *dev)
/* Restart periodic output signal */
next = ns_to_timespec64(next_ns);
- request.start.sec = next.tv_sec;
- request.start.nsec = next.tv_nsec;
- request.period.sec = ptp_data->perout_period.tv_sec;
- request.period.nsec = ptp_data->perout_period.tv_nsec;
- request.index = 0;
- request.flags = 0;
+ request->start.sec = next.tv_sec;
+ request->start.nsec = next.tv_nsec;
+ request->period.sec = ptp_data->perout_period.tv_sec;
+ request->period.nsec = ptp_data->perout_period.tv_nsec;
+ request->index = 0;
+ request->flags = 0;
+
+ return 0;
+}
+
+static int ksz_ptp_restart_perout(struct ksz_device *dev)
+{
+ struct ptp_perout_request request;
+ int ret;
+
+ ret = ksz_ptp_prepare_restart_perout(dev, &request);
+ if (ret)
+ return ret;
return ksz_ptp_enable_perout(dev, &request, 1);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next v2 08/10] net: dsa: microchip: extract time update
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
` (6 preceding siblings ...)
2026-09-02 9:57 ` [PATCH net-next v2 07/10] net: dsa: microchip: extract prepare reset Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 09/10] net: dsa: microchip: extract time adjustment Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 10/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The KSZ8463 supports periodic outputs but doesn't handle them in the same
way as the other KSZ switches. To add proper support for the KSZ8463, a
dedicated ksz8463_ptp_settime() function needs to be created. This
function will access the same registers than the common
ksz_ptp_settime().
Extract the register accesses into a dedicated function so it can be
used later by the KSZ8463 support.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_ptp.c | 30 +++++++++++++++++++++---------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index e262bc7448f2..aa73ad1f05d8 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -845,30 +845,42 @@ static int ksz_ptp_restart_perout(struct ksz_device *dev)
return ksz_ptp_enable_perout(dev, &request, 1);
}
-static int ksz_ptp_settime(struct ptp_clock_info *ptp,
- const struct timespec64 *ts)
+static int __ksz_ptp_settime(struct ksz_device *dev,
+ const struct timespec64 *ts)
{
- struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
- struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
const u16 *regs = dev->info->regs;
int ret;
- mutex_lock(&ptp_data->lock);
-
/* Write to shadow registers and Load PTP clock */
ret = ksz_write16(dev, regs[PTP_RTC_SUB_NANOSEC], PTP_RTC_0NS);
if (ret)
- goto unlock;
+ return ret;
ret = ksz_write32(dev, regs[PTP_RTC_NANOSEC], ts->tv_nsec);
if (ret)
- goto unlock;
+ return ret;
ret = ksz_write32(dev, regs[PTP_RTC_SEC], ts->tv_sec);
if (ret)
- goto unlock;
+ return ret;
ret = ksz_rmw16(dev, regs[PTP_CLK_CTRL], PTP_LOAD_TIME, PTP_LOAD_TIME);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ksz_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
+ struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
+ int ret;
+
+ mutex_lock(&ptp_data->lock);
+
+ ret = __ksz_ptp_settime(dev, ts);
if (ret)
goto unlock;
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next v2 09/10] net: dsa: microchip: extract time adjustment
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
` (7 preceding siblings ...)
2026-09-02 9:57 ` [PATCH net-next v2 08/10] net: dsa: microchip: extract time update Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-02 9:57 ` [PATCH net-next v2 10/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
The KSZ8463 supports periodic outputs but doesn't handle them in the same
way as the other KSZ switches. To add proper support for the KSZ8463, a
dedicated ksz8463_ptp_adjtime() function needs to be created. This
function will access the same registers as the common ksz_ptp_adjtime()
function.
Extract the register accesses into a dedicated function so it can be
used later by the KSZ8463 support.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz_ptp.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index aa73ad1f05d8..0a77b46cfad2 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -946,18 +946,13 @@ static int ksz_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
return ret;
}
-static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+static int __ksz_ptp_adjtime(struct ksz_device *dev, s64 delta)
{
- struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
- struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
- struct timespec64 delta64 = ns_to_timespec64(delta);
const u16 *regs = dev->info->regs;
s32 sec, nsec;
u16 data16;
int ret;
- mutex_lock(&ptp_data->lock);
-
/* do not use ns_to_timespec64(),
* both sec and nsec are subtracted by hw
*/
@@ -965,15 +960,15 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
ret = ksz_write32(dev, regs[PTP_RTC_NANOSEC], abs(nsec));
if (ret)
- goto unlock;
+ return ret;
ret = ksz_write32(dev, regs[PTP_RTC_SEC], abs(sec));
if (ret)
- goto unlock;
+ return ret;
ret = ksz_read16(dev, regs[PTP_CLK_CTRL], &data16);
if (ret)
- goto unlock;
+ return ret;
data16 |= PTP_STEP_ADJ;
@@ -984,6 +979,22 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
data16 |= PTP_STEP_DIR;
ret = ksz_write16(dev, regs[PTP_CLK_CTRL], data16);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
+ struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
+ struct timespec64 delta64 = ns_to_timespec64(delta);
+ int ret;
+
+ mutex_lock(&ptp_data->lock);
+
+ ret = __ksz_ptp_adjtime(dev, delta);
if (ret)
goto unlock;
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next v2 10/10] net: dsa: microchip: add periodic output support for the KSZ8463
2026-09-02 9:57 [PATCH net-next v2 00/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
` (8 preceding siblings ...)
2026-09-02 9:57 ` [PATCH net-next v2 09/10] net: dsa: microchip: extract time adjustment Bastien Curutchet (Schneider Electric)
@ 2026-09-02 9:57 ` Bastien Curutchet (Schneider Electric)
2026-09-05 1:55 ` netdev-bot+sashiko
9 siblings, 1 reply; 14+ messages in thread
From: Bastien Curutchet (Schneider Electric) @ 2026-09-02 9:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Richard Cochran
Cc: Pascal Eberhard, Miquèl Raynal, Thomas Petazzoni, netdev,
linux-kernel, Bastien Curutchet (Schneider Electric)
KSZ8463 has several periodic outputs. The way it handles them differ
from the other KSZ switches:
- KSZ8463 has one set of registers for each of its 12 units while others
switches share on set of configuration registers for all their units.
- Maximum size of the KSZ8463 pulse width is smaller
- KSZ8463 has 12 outputs while others only have 2
Add support for the KSZ8463 periodics outputs through a set of KSZ8463
specific functions.
Signed-off-by: Bastien Curutchet (Schneider Electric) <bastien.curutchet@bootlin.com>
---
drivers/net/dsa/microchip/ksz8.c | 2 +-
drivers/net/dsa/microchip/ksz_common.c | 2 +
drivers/net/dsa/microchip/ksz_ptp.c | 258 ++++++++++++++++++++++++++++++++
drivers/net/dsa/microchip/ksz_ptp.h | 3 +-
drivers/net/dsa/microchip/ksz_ptp_reg.h | 16 ++
5 files changed, 279 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
index f2a23e2e474a..6b08bb8fed5b 100644
--- a/drivers/net/dsa/microchip/ksz8.c
+++ b/drivers/net/dsa/microchip/ksz8.c
@@ -2478,7 +2478,7 @@ static int ksz8463_setup(struct dsa_switch *ds)
if (ret)
goto free_girq;
- ksz_ptp_set_caps(ds);
+ ksz8463_ptp_set_caps(ds);
ret = ksz_ptp_clock_register(ds);
if (ret) {
dev_err(dev->dev, "Failed to register PTP clock: %d\n",
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 041bb4f96365..9e234ad71b72 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -1161,6 +1161,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.supports_mii = {false, false, true},
.supports_rmii = {false, false, true},
.internal_phy = {true, true, false},
+ .n_pins = 12,
+ .n_per_out = 12,
},
[KSZ8563] = {
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index 0a77b46cfad2..d33034892a8f 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -26,6 +26,7 @@
*/
#define KSZ_MAX_DRIFT_CORR 6249999
#define KSZ_MAX_PULSE_WIDTH 125000000LL
+#define KSZ8463_MAX_PULSE_WIDTH 500000LL
#define KSZ_PTP_INC_NS 40ULL /* HW clock is incremented every 40 ns (by 40) */
#define KSZ_PTP_SUBNS_BITS 32
@@ -63,6 +64,17 @@ static int ksz_ptp_tou_gpio(struct ksz_device *dev)
LED_SRC_PTP_GPIO_1 | LED_SRC_PTP_GPIO_2);
}
+static int ksz8463_ptp_tou_reset(struct ksz_device *dev, u8 unit)
+{
+ int ret;
+
+ ret = ksz_rmw16(dev, KSZ8463_TOU_SW_RST, BIT(unit), BIT(unit));
+ if (ret)
+ return ret;
+
+ return ksz_rmw16(dev, KSZ8463_TOU_SW_RST, BIT(unit), 0);
+}
+
static int ksz_ptp_tou_reset(struct ksz_device *dev, u8 unit)
{
u32 data;
@@ -120,6 +132,28 @@ static int ksz_ptp_tou_target_time_set(struct ksz_device *dev,
return 0;
}
+static int ksz8463_ptp_tou_start(struct ksz_device *dev, u8 unit)
+{
+ u16 data;
+ int ret;
+
+ ret = ksz_rmw16(dev, KSZ8463_TOU_EN, BIT(unit), BIT(unit));
+ if (ret)
+ return ret;
+
+ ret = ksz_read16(dev, KSZ8463_TOU_ACTIVE, &data);
+ if (ret)
+ return ret;
+
+ if (!(data & BIT(unit))) {
+ dev_err(dev->dev, "%s: Trigger unit%d error!\n", __func__,
+ unit);
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int ksz_ptp_tou_start(struct ksz_device *dev, u8 unit)
{
u32 data;
@@ -147,6 +181,56 @@ static int ksz_ptp_tou_start(struct ksz_device *dev, u8 unit)
return 0;
}
+static int ksz8463_ptp_configure_perout(struct ksz_device *dev,
+ u32 cycle_width_ns, u32 pulse_width_ns,
+ struct timespec64 const *target_time,
+ u8 index)
+{
+ struct ptp_pin_desc *pin = &dev->ptp_data.pin_config[index];
+ u16 cfg_base = KSZ8463_TRIG1_CFG + KSZ8463_TRIGN_CFG_SIZE * pin->chan;
+ u16 data;
+ int ret;
+
+ /* Hardware has only 32 bit */
+ if ((target_time->tv_sec & 0xffffffff) != target_time->tv_sec)
+ return -EINVAL;
+
+ data = KSZ8463_NOTIFY_BIT |
+ FIELD_PREP(KSZ8463_PATTERN_M, TRIG_POS_PERIOD) |
+ pin->index;
+ ret = ksz_write16(dev, cfg_base + KSZ8463_PATTERN_OFF, data);
+ if (ret)
+ return ret;
+
+ ret = ksz_write32(dev, cfg_base + KSZ8463_CYCLE_WIDTH_OFF,
+ cycle_width_ns);
+ if (ret)
+ return ret;
+
+ /* Set cycle count 0 - Infinite */
+ ret = ksz_write16(dev, cfg_base + KSZ8463_CYCLE_CNT_OFF, 0);
+ if (ret)
+ return ret;
+
+ /* KSZ8463 uses a 8 ns unit value to compute the pulse width */
+ data = (pulse_width_ns / 8);
+ ret = ksz_write16(dev, cfg_base + KSZ8463_PULSE_WIDTH_OFF, data);
+ if (ret)
+ return ret;
+
+ ret = ksz_write32(dev, cfg_base + KSZ8463_TARGET_NSEC,
+ target_time->tv_nsec);
+ if (ret)
+ return ret;
+
+ ret = ksz_write32(dev, cfg_base + KSZ8463_TARGET_SEC,
+ target_time->tv_sec);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int ksz_ptp_configure_perout(struct ksz_device *dev,
u32 cycle_width_ns, u32 pulse_width_ns,
struct timespec64 const *target_time,
@@ -241,6 +325,58 @@ static u64 ksz_ptp_compute_perout_pulse(struct ksz_device *dev,
return min_t(u64, req_pulse_width_ns, max_pulse_width);
}
+static int ksz8463_ptp_enable_perout(struct ksz_device *dev,
+ struct ptp_perout_request const *request,
+ int on)
+{
+ struct ksz_ptp_data *ptp_data = &dev->ptp_data;
+ u64 cycle_width_ns;
+ u64 pulse_width_ns;
+ int pin;
+ int ret;
+
+ pin = ksz_ptp_get_pin(dev, request);
+ if (pin < 0)
+ return pin;
+
+ ret = ksz8463_ptp_tou_reset(dev, request->index);
+ if (ret)
+ return ret;
+
+ if (!on) {
+ ptp_data->tou_mode = KSZ_PTP_TOU_IDLE;
+ return 0;
+ }
+ ret = ksz_ptp_compute_perout_cycle(dev, request, &cycle_width_ns);
+ if (ret)
+ return ret;
+ pulse_width_ns = ksz_ptp_compute_perout_pulse(dev, request,
+ KSZ8463_MAX_PULSE_WIDTH);
+
+ ret = ksz_ptp_tou_pulse_verify(pulse_width_ns,
+ KSZ8463_TRIG_PULSE_WIDTH_M);
+ if (ret)
+ return ret;
+
+ ret = ksz8463_ptp_configure_perout(dev, cycle_width_ns, pulse_width_ns,
+ &ptp_data->perout_target_time_first,
+ pin);
+ if (ret)
+ return ret;
+
+ ret = ksz_ptp_tou_gpio(dev);
+ if (ret)
+ return ret;
+
+ ret = ksz8463_ptp_tou_start(dev, request->index);
+ if (ret)
+ return ret;
+
+ ptp_data->tou_mode = KSZ_PTP_TOU_PEROUT;
+
+ return 0;
+}
+
static int ksz_ptp_enable_perout(struct ksz_device *dev,
struct ptp_perout_request const *request,
int on)
@@ -845,6 +981,18 @@ static int ksz_ptp_restart_perout(struct ksz_device *dev)
return ksz_ptp_enable_perout(dev, &request, 1);
}
+static int ksz8463_ptp_restart_perout(struct ksz_device *dev)
+{
+ struct ptp_perout_request request;
+ int ret;
+
+ ret = ksz_ptp_prepare_restart_perout(dev, &request);
+ if (ret)
+ return ret;
+
+ return ksz8463_ptp_enable_perout(dev, &request, 1);
+}
+
static int __ksz_ptp_settime(struct ksz_device *dev,
const struct timespec64 *ts)
{
@@ -871,6 +1019,41 @@ static int __ksz_ptp_settime(struct ksz_device *dev,
return 0;
}
+static int ksz8463_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
+ struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
+ int ret;
+
+ mutex_lock(&ptp_data->lock);
+
+ ret = __ksz_ptp_settime(dev, ts);
+ if (ret)
+ goto unlock;
+
+ switch (ptp_data->tou_mode) {
+ case KSZ_PTP_TOU_IDLE:
+ break;
+
+ case KSZ_PTP_TOU_PEROUT:
+ ret = ksz8463_ptp_restart_perout(dev);
+ if (ret)
+ goto unlock;
+
+ break;
+ }
+
+ spin_lock_bh(&ptp_data->clock_lock);
+ ptp_data->clock_time = *ts;
+ spin_unlock_bh(&ptp_data->clock_lock);
+
+unlock:
+ mutex_unlock(&ptp_data->lock);
+
+ return ret;
+}
+
static int ksz_ptp_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
@@ -985,6 +1168,40 @@ static int __ksz_ptp_adjtime(struct ksz_device *dev, s64 delta)
return 0;
}
+static int ksz8463_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
+ struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
+ struct timespec64 delta64 = ns_to_timespec64(delta);
+ int ret;
+
+ mutex_lock(&ptp_data->lock);
+
+ ret = __ksz_ptp_adjtime(dev, delta);
+ if (ret)
+ goto unlock;
+
+ switch (ptp_data->tou_mode) {
+ case KSZ_PTP_TOU_IDLE:
+ break;
+
+ case KSZ_PTP_TOU_PEROUT:
+ ret = ksz8463_ptp_restart_perout(dev);
+ if (ret)
+ goto unlock;
+
+ break;
+ }
+
+ spin_lock_bh(&ptp_data->clock_lock);
+ ptp_data->clock_time = timespec64_add(ptp_data->clock_time, delta64);
+ spin_unlock_bh(&ptp_data->clock_lock);
+
+unlock:
+ mutex_unlock(&ptp_data->lock);
+ return ret;
+}
+
static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
@@ -1019,6 +1236,26 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
return ret;
}
+static int ksz8463_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *req, int on)
+{
+ struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
+ struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
+ int ret;
+
+ switch (req->type) {
+ case PTP_CLK_REQ_PEROUT:
+ mutex_lock(&ptp_data->lock);
+ ret = ksz8463_ptp_enable_perout(dev, &req->perout, on);
+ mutex_unlock(&ptp_data->lock);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
static int ksz_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *req, int on)
{
@@ -1095,6 +1332,27 @@ static int ksz_ptp_start_clock(struct ksz_device *dev)
return 0;
}
+void ksz8463_ptp_set_caps(struct dsa_switch *ds)
+{
+ struct ksz_device *dev = ds->priv;
+ struct ksz_ptp_data *ptp_data;
+
+ ptp_data = &dev->ptp_data;
+
+ ptp_data->caps.owner = THIS_MODULE;
+ snprintf(ptp_data->caps.name, 16, "Microchip Clock");
+ ptp_data->caps.max_adj = KSZ_MAX_DRIFT_CORR;
+ ptp_data->caps.gettime64 = ksz_ptp_gettime;
+ ptp_data->caps.settime64 = ksz8463_ptp_settime;
+ ptp_data->caps.adjfine = ksz_ptp_adjfine;
+ ptp_data->caps.adjtime = ksz8463_ptp_adjtime;
+ ptp_data->caps.do_aux_work = ksz_ptp_do_aux_work;
+ ptp_data->caps.enable = ksz8463_ptp_enable;
+ ptp_data->caps.verify = ksz_ptp_verify_pin;
+ ptp_data->caps.n_pins = dev->info->n_pins;
+ ptp_data->caps.n_per_out = dev->info->n_per_out;
+}
+
void ksz_ptp_set_caps(struct dsa_switch *ds)
{
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 89716b31596b..92589cf373ac 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.h
+++ b/drivers/net/dsa/microchip/ksz_ptp.h
@@ -12,7 +12,7 @@
#include <linux/ptp_clock_kernel.h>
-#define KSZ_PTP_N_GPIO 2
+#define KSZ_PTP_N_GPIO 12
enum ksz_ptp_tou_mode {
KSZ_PTP_TOU_IDLE,
@@ -34,6 +34,7 @@ struct ksz_ptp_data {
};
void ksz_ptp_set_caps(struct dsa_switch *ds);
+void ksz8463_ptp_set_caps(struct dsa_switch *ds);
int ksz_ptp_clock_register(struct dsa_switch *ds);
void ksz_ptp_clock_unregister(struct dsa_switch *ds);
diff --git a/drivers/net/dsa/microchip/ksz_ptp_reg.h b/drivers/net/dsa/microchip/ksz_ptp_reg.h
index 65ea8577af75..16f117fa5d49 100644
--- a/drivers/net/dsa/microchip/ksz_ptp_reg.h
+++ b/drivers/net/dsa/microchip/ksz_ptp_reg.h
@@ -51,6 +51,22 @@
#define REG_PTP_UNIT_INDEX__4 0x0520
+#define KSZ8463_TOU_ACTIVE 0x202
+#define KSZ8463_TOU_EN 0x206
+#define KSZ8463_TOU_SW_RST 0x208
+
+#define KSZ8463_TRIGN_CFG_SIZE 0x20
+#define KSZ8463_TRIG1_CFG 0x220
+#define KSZ8463_TARGET_NSEC 0x000
+#define KSZ8463_TARGET_SEC 0x004
+#define KSZ8463_PATTERN_OFF 0x008
+#define KSZ8463_NOTIFY_BIT BIT(8)
+#define KSZ8463_PATTERN_M GENMASK(6, 4)
+#define KSZ8463_PULSE_WIDTH_OFF 0x00A
+#define KSZ8463_TRIG_PULSE_WIDTH_M GENMASK(15, 0)
+#define KSZ8463_CYCLE_WIDTH_OFF 0x00C
+#define KSZ8463_CYCLE_CNT_OFF 0x010
+
#define PTP_GPIO_INDEX GENMASK(19, 16)
#define PTP_TSI_INDEX BIT(8)
#define PTP_TOU_INDEX GENMASK(1, 0)
--
2.55.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH net-next v2 10/10] net: dsa: microchip: add periodic output support for the KSZ8463
2026-09-02 9:57 ` [PATCH net-next v2 10/10] net: dsa: microchip: add periodic output support for the KSZ8463 Bastien Curutchet (Schneider Electric)
@ 2026-09-05 1:55 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-09-05 1:55 UTC (permalink / raw)
To: bastien.curutchet
Cc: woojung.huh, UNGLinuxDriver, andrew, olteanv, davem, edumazet,
kuba, pabeni, richardcochran, pascal.eberhard, miquel.raynal,
thomas.petazzoni, netdev, linux-kernel
Thank you for your contribution! Sashiko AI review found 5 potential
issue(s) to consider:
Critical: 0 · High: 2 (1) · Medium: 3 · Low: 0 (2)
- [High] KSZ8463 periodic output is advertised as 12 independent channels
(.n_pins = 12, .n_per_out = 12 in ksz_switch_chips[KSZ8463]) but the…
- [High] KSZ8463 periodic output (TOU) is not properly disabled in
hardware (leaves EN bit).
- [Medium] Build failure when CONFIG_NET_DSA_MICROCHIP_KSZ_PTP=n:
ksz8463_setup() in drivers/net/dsa/microchip/ksz8.c now calls…
- [Medium] The newly added ksz8463_ptp_configure_perout() dereferences
dev->ptp_data.pin_config[index] (reading pin->chan to select the…
- [Medium] KSZ8463 TOU enable bit is left set in the hardware if the
activation verification check fails.
Pre-existing issues:
- [High] A non-normalized periodic-output period whose nanosecond value
converts to zero is accepted, stored as the global restart period, and…
- [Low] The KSZ periodic-output implementation accepts and processes
PTP_PEROUT_DUTY_CYCLE (ksz_ptp_get_pin() returns -EOPNOTSUPP only for…
- [Low] ksz_ptp_clock_unregister() only calls ptp_clock_unregister(); it
never disables the trigger units that the perout path enabled.
--
net: dsa: microchip: add periodic output support for the KSZ8463
This adds KSZ8463 specific periodic output handling, since the chip has one
configuration register block per trigger unit, a smaller maximum pulse
width and 12 outputs instead of 2. It wires new ksz8463_ptp_* callbacks
into a dedicated ksz8463_ptp_set_caps() and advertises 12 pins / 12
periodic output channels for the KSZ8463.
A few questions on the new code below.
> diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
> index f2a23e2e474ac..6b08bb8fed5b7 100644
> --- a/drivers/net/dsa/microchip/ksz8.c
> +++ b/drivers/net/dsa/microchip/ksz8.c
> @@ -2478,7 +2478,7 @@ static int ksz8463_setup(struct dsa_switch *ds)
> if (ret)
> goto free_girq;
>
> - ksz_ptp_set_caps(ds);
> + ksz8463_ptp_set_caps(ds);
[Severity: Medium]
Does this still build with CONFIG_NET_DSA_MICROCHIP_KSZ_PTP=n?
This call site is not inside any #ifdef (it is only guarded by
"if (dev->irq > 0)"), and ksz_ptp.h declares the new symbol only in the
PTP-enabled branch:
drivers/net/dsa/microchip/ksz_ptp.h
#if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP)
...
void ksz_ptp_set_caps(struct dsa_switch *ds);
void ksz8463_ptp_set_caps(struct dsa_switch *ds);
The #else branch stubs every other PTP entry point that ksz8.c uses
(ksz_ptp_set_caps(), ksz_ptp_clock_register(), ksz_ptp_clock_unregister(),
ksz8463_ptp_irq_setup(), ksz8463_ptp_irq_free()) but has no stub for
ksz8463_ptp_set_caps():
static inline void ksz_ptp_set_caps(struct dsa_switch *ds) { }
ksz_ptp.o is also not linked in that configuration, since the Makefile
guards it with "ifdef CONFIG_NET_DSA_MICROCHIP_KSZ_PTP". Previously this
line called ksz_ptp_set_caps(), which does have a stub. Would adding
"static inline void ksz8463_ptp_set_caps(struct dsa_switch *ds) { }" to the
#else branch be the intent?
> ret = ksz_ptp_clock_register(ds);
> if (ret) {
> dev_err(dev->dev, "Failed to register PTP clock: %d\n",
> diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
> index 041bb4f963659..9e234ad71b723 100644
> --- a/drivers/net/dsa/microchip/ksz_common.c
> +++ b/drivers/net/dsa/microchip/ksz_common.c
> @@ -1161,6 +1161,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
> .supports_mii = {false, false, true},
> .supports_rmii = {false, false, true},
> .internal_phy = {true, true, false},
> + .n_pins = 12,
> + .n_per_out = 12,
> },
>
> [KSZ8563] = {
> diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
> index 0a77b46cfad25..d33034892a8f6 100644
> --- a/drivers/net/dsa/microchip/ksz_ptp.c
> +++ b/drivers/net/dsa/microchip/ksz_ptp.c
[ ... ]
> @@ -120,6 +132,28 @@ static int ksz_ptp_tou_target_time_set(struct ksz_device *dev,
> return 0;
> }
>
> +static int ksz8463_ptp_tou_start(struct ksz_device *dev, u8 unit)
> +{
> + u16 data;
> + int ret;
> +
> + ret = ksz_rmw16(dev, KSZ8463_TOU_EN, BIT(unit), BIT(unit));
> + if (ret)
> + return ret;
[Severity: High]
Does the software reset actually stop the pulse train, or does
KSZ8463_TOU_EN have to be cleared as well?
ksz8463_ptp_tou_reset() only pulses BIT(unit) in KSZ8463_TOU_SW_RST
and leaves KSZ8463_TOU_EN untouched, but that is the register
ksz8463_ptp_tou_start() writes to arm the unit. Compare the generic
path: ksz_ptp_tou_reset() explicitly drops the enable bit as its last
step,
/* Clear reset and set GPIO direction */
return ksz_rmw32(dev, REG_PTP_CTRL_STAT__4, (TRIG_RESET | TRIG_ENABLE),
0);
while the KSZ8463 version has no equivalent for BIT(unit) in
KSZ8463_TOU_EN.
That matters for the disable path in ksz8463_ptp_enable_perout(),
which handles "on == 0" purely by calling ksz8463_ptp_tou_reset() and
then setting ptp_data->tou_mode to KSZ_PTP_TOU_IDLE. If the enable
bit survives the reset, a PTP_PEROUT_REQUEST with a zero period keeps
the output toggling on the pin while software believes the unit is
idle, so settime/adjtime will no longer even realign it. Reachable
from plain userspace: enable a perout on /dev/ptpN, then disable it.
Could you confirm against the datasheet whether writing SW_RST
self-clears TOU_EN? If it does not, should the !on branch (or
ksz8463_ptp_tou_reset() itself, mirroring ksz_ptp_tou_reset()) also
clear BIT(unit) in KSZ8463_TOU_EN?
[Severity: Low]
This isn't an issue introduced by this patch, but once a unit has been
armed here via KSZ8463_TOU_EN, is anything expected to turn it off at
teardown? ksz_ptp_clock_unregister() only does:
ptp_data = &dev->ptp_data;
if (ptp_data->clock)
ptp_clock_unregister(ptp_data->clock);
so after unbinding the driver the enabled trigger units keep toggling the
pins with no owning software state. The same gap already exists for the
ksz9477/lan937x trigger units, so this is only an observation about the new
users of that path.
> +
> + ret = ksz_read16(dev, KSZ8463_TOU_ACTIVE, &data);
> + if (ret)
> + return ret;
> +
> + if (!(data & BIT(unit))) {
> + dev_err(dev->dev, "%s: Trigger unit%d error!\n", __func__,
> + unit);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> static int ksz_ptp_tou_start(struct ksz_device *dev, u8 unit)
> {
> u32 data;
> @@ -147,6 +181,56 @@ static int ksz_ptp_tou_start(struct ksz_device *dev, u8 unit)
> return 0;
> }
>
> +static int ksz8463_ptp_configure_perout(struct ksz_device *dev,
> + u32 cycle_width_ns, u32 pulse_width_ns,
> + struct timespec64 const *target_time,
> + u8 index)
> +{
> + struct ptp_pin_desc *pin = &dev->ptp_data.pin_config[index];
> + u16 cfg_base = KSZ8463_TRIG1_CFG + KSZ8463_TRIGN_CFG_SIZE * pin->chan;
[Severity: Medium]
Should this error path undo the KSZ8463_TOU_EN write that precedes
it?
ksz8463_ptp_tou_start() sets BIT(unit) in KSZ8463_TOU_EN and then
returns -EIO if the unit does not show up in KSZ8463_TOU_ACTIVE,
leaving the enable bit set in hardware. The caller,
ksz8463_ptp_enable_perout(), propagates the error without setting
ptp_data->tou_mode, so the unit is left armed with no software state
claiming it.
The generic ksz_ptp_tou_start() can get away with a bare return
because of its "Unit will be reset on next access" assumption:
ksz_ptp_tou_reset() clears TRIG_ENABLE at the start of the next
enable. As noted on ksz8463_ptp_tou_reset(), the KSZ8463 reset only
toggles KSZ8463_TOU_SW_RST and never touches KSZ8463_TOU_EN, so that
assumption does not carry over here and the stale enable bit is not
cleaned up on the next request either.
Would clearing BIT(unit) in KSZ8463_TOU_EN before returning -EIO be
the right thing, or is it preferable to make ksz8463_ptp_tou_reset()
clear the enable bit so the existing "reset on next access" pattern
holds for this chip too?
[Severity: Medium]
Which lock protects pin_config[] here?
pin_config is owned by the PTP core and documented as protected by
ptp_clock::pincfg_mux in drivers/ptp/ptp_private.h:
struct mutex pincfg_mux; /* protect concurrent info->pin_config access */
The core takes that mutex around the enable() callback, but the new restart
path reaches this function from clock_settime()/clock_adjtime() with only
ptp_data->lock held:
ksz8463_ptp_settime()/ksz8463_ptp_adjtime()
-> ksz8463_ptp_restart_perout()
-> ksz8463_ptp_enable_perout()
-> ksz_ptp_get_pin() /* calls ptp_find_pin() */
-> ksz8463_ptp_configure_perout()
Meanwhile PTP_PIN_SETFUNC writes pin->func and pin->chan in
ptp_set_pinfunc() under pincfg_mux only. If chan changes while this runs,
cfg_base can select a different trigger unit's register block than the one
ksz8463_ptp_tou_reset()/ksz8463_ptp_tou_start() operate on
(request->index), so one unit gets programmed while another gets reset and
enabled.
Note that simply switching to ptp_find_pin_unlocked() would invert the lock
order against the enable() path, which already holds pincfg_mux before
ptp_data->lock. Would snapshotting pin index and chan under ptp_data->lock
at enable() time work better?
The bare ptp_find_pin() call from settime/adjtime predates this patch for
ksz9477/lan937x; the new part is deriving a register block address from
pin->chan on that path.
> + u16 data;
> + int ret;
> +
> + /* Hardware has only 32 bit */
> + if ((target_time->tv_sec & 0xffffffff) != target_time->tv_sec)
> + return -EINVAL;
> +
> + data = KSZ8463_NOTIFY_BIT |
> + FIELD_PREP(KSZ8463_PATTERN_M, TRIG_POS_PERIOD) |
> + pin->index;
> + ret = ksz_write16(dev, cfg_base + KSZ8463_PATTERN_OFF, data);
> + if (ret)
> + return ret;
> +
[ ... ]
> + return 0;
> +}
> +
> static int ksz_ptp_configure_perout(struct ksz_device *dev,
> u32 cycle_width_ns, u32 pulse_width_ns,
> struct timespec64 const *target_time,
> @@ -241,6 +325,58 @@ static u64 ksz_ptp_compute_perout_pulse(struct ksz_device *dev,
> return min_t(u64, req_pulse_width_ns, max_pulse_width);
> }
>
> +static int ksz8463_ptp_enable_perout(struct ksz_device *dev,
> + struct ptp_perout_request const *request,
> + int on)
> +{
> + struct ksz_ptp_data *ptp_data = &dev->ptp_data;
> + u64 cycle_width_ns;
> + u64 pulse_width_ns;
> + int pin;
> + int ret;
> +
> + pin = ksz_ptp_get_pin(dev, request);
> + if (pin < 0)
> + return pin;
> +
> + ret = ksz8463_ptp_tou_reset(dev, request->index);
> + if (ret)
> + return ret;
> +
> + if (!on) {
> + ptp_data->tou_mode = KSZ_PTP_TOU_IDLE;
> + return 0;
> + }
> + ret = ksz_ptp_compute_perout_cycle(dev, request, &cycle_width_ns);
> + if (ret)
> + return ret;
[Severity: High]
This isn't a bug introduced by this patch, but the new KSZ8463 path
inherits it, so it may be worth a look: can a period of 0 ns be stored and
later used as a divisor?
ksz_ptp_compute_perout_cycle() saves the request into ptp_data before
validating it, and only checks that the converted value fits the cycle
width mask:
ptp_data->perout_period.tv_sec = request->period.sec;
ptp_data->perout_period.tv_nsec = request->period.nsec;
*cycle_width_ns = timespec64_to_ns(&ptp_data->perout_period);
if ((*cycle_width_ns & TRIG_CYCLE_WIDTH_M) != *cycle_width_ns) {
A non-normalized request with period.sec = -1 and period.nsec = 1000000000
is treated as "enable" by the core (perout->period.sec || perout->period.nsec
is true) and converts to 0 ns, which passes the mask check. The default
pulse width then also computes to 0 and passes ksz_ptp_tou_pulse_verify().
No error path in ksz8463_ptp_enable_perout() resets tou_mode, so after a
previous successful enable the state stays KSZ_PTP_TOU_PEROUT with
perout_period converting to 0. The next clock_settime()/clock_adjtime()
then runs ksz_ptp_prepare_restart_perout() with period_ns == 0:
count = div_u64(now_ns - first_ns, period_ns);
...
while (next_ns < now_ns + 100000000)
next_ns += period_ns;
which is a divide-by-zero on x86-64, and on arm64 (where UDIV by zero
returns 0) the loop never terminates while ptp_data->lock is held. Would
rejecting a period whose nanosecond conversion is zero, and only committing
perout_period after validation, be appropriate here?
> + pulse_width_ns = ksz_ptp_compute_perout_pulse(dev, request,
> + KSZ8463_MAX_PULSE_WIDTH);
> +
> + ret = ksz_ptp_tou_pulse_verify(pulse_width_ns,
> + KSZ8463_TRIG_PULSE_WIDTH_M);
> + if (ret)
> + return ret;
> +
> + ret = ksz8463_ptp_configure_perout(dev, cycle_width_ns, pulse_width_ns,
> + &ptp_data->perout_target_time_first,
> + pin);
> + if (ret)
> + return ret;
> +
> + ret = ksz_ptp_tou_gpio(dev);
> + if (ret)
> + return ret;
> +
> + ret = ksz8463_ptp_tou_start(dev, request->index);
> + if (ret)
> + return ret;
> +
> + ptp_data->tou_mode = KSZ_PTP_TOU_PEROUT;
> +
> + return 0;
> +}
> +
> static int ksz_ptp_enable_perout(struct ksz_device *dev,
> struct ptp_perout_request const *request,
> int on)
> @@ -845,6 +981,18 @@ static int ksz_ptp_restart_perout(struct ksz_device *dev)
> return ksz_ptp_enable_perout(dev, &request, 1);
> }
>
> +static int ksz8463_ptp_restart_perout(struct ksz_device *dev)
> +{
> + struct ptp_perout_request request;
> + int ret;
> +
> + ret = ksz_ptp_prepare_restart_perout(dev, &request);
> + if (ret)
> + return ret;
> +
> + return ksz8463_ptp_enable_perout(dev, &request, 1);
> +}
[Severity: High]
Can a periodic output on a channel other than 0 be restarted after a clock
step? ksz_ptp_prepare_restart_perout() hardcodes the channel:
request->index = 0;
request->flags = 0;
So with an output running on, say, channel 5:
ksz8463_ptp_settime()
-> ksz8463_ptp_restart_perout()
-> ksz_ptp_prepare_restart_perout() /* request->index = 0 */
-> ksz8463_ptp_enable_perout()
-> ksz_ptp_get_pin()
-> ptp_find_pin(clock, PTP_PF_PEROUT, 0) /* no match, -1 */
ksz_ptp_get_pin() then returns -EINVAL, which is propagated out of
ksz8463_ptp_settime()/ksz8463_ptp_adjtime() after
__ksz_ptp_settime()/__ksz_ptp_adjtime() already reprogrammed the hardware
RTC. The output is never realigned, the ioctl reports failure although the
clock did change, and the "goto unlock" also skips the ptp_data->clock_time
update used by ksz_tstamp_reconstruct() (that mirror is otherwise only
re-synced from ksz_ptp_do_aux_work(), which runs only while a port has
hardware timestamping enabled).
The reachable sequence is a plain /dev/ptpN one: PTP_PIN_SETFUNC assigns
pin 5 to PTP_PF_PEROUT chan 5 (ksz_ptp_verify_pin() accepts PTP_PF_PEROUT
for any pin/chan and ptp_set_pinfunc() only requires chan < n_per_out = 12),
then PTP_PEROUT_REQUEST index 5 succeeds and sets tou_mode =
KSZ_PTP_TOU_PEROUT, then clock_settime() or clock_adjtime().
Two related points on the same singleton state, now that .n_per_out = 12 is
advertised for the KSZ8463:
If some pin does happen to be mapped to chan 0, the restart reprograms and
starts trigger unit 0 using the globally shared perout_period and
perout_target_time_first of whichever channel was configured last, so the
wrong unit is armed while the running unit keeps a stale target time.
Also, the !on branch of ksz8463_ptp_enable_perout() sets the single
tou_mode to KSZ_PTP_TOU_IDLE no matter which of the 12 units was disabled:
if (!on) {
ptp_data->tou_mode = KSZ_PTP_TOU_IDLE;
return 0;
}
after which settime/adjtime take the IDLE case and any still-enabled unit
is not restarted at all.
Should struct ksz_ptp_data keep tou_mode, perout_period and
perout_target_time_first per unit, with the channel index preserved in the
restart request?
> +
> static int __ksz_ptp_settime(struct ksz_device *dev,
> const struct timespec64 *ts)
> {
> @@ -871,6 +1019,41 @@ static int __ksz_ptp_settime(struct ksz_device *dev,
> return 0;
> }
>
> +static int ksz8463_ptp_settime(struct ptp_clock_info *ptp,
> + const struct timespec64 *ts)
> +{
> + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp);
> + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data);
> + int ret;
> +
> + mutex_lock(&ptp_data->lock);
> +
> + ret = __ksz_ptp_settime(dev, ts);
> + if (ret)
> + goto unlock;
> +
> + switch (ptp_data->tou_mode) {
> + case KSZ_PTP_TOU_IDLE:
> + break;
> +
> + case KSZ_PTP_TOU_PEROUT:
> + ret = ksz8463_ptp_restart_perout(dev);
> + if (ret)
> + goto unlock;
> +
> + break;
> + }
> +
> + spin_lock_bh(&ptp_data->clock_lock);
> + ptp_data->clock_time = *ts;
> + spin_unlock_bh(&ptp_data->clock_lock);
> +
> +unlock:
> + mutex_unlock(&ptp_data->lock);
> +
> + return ret;
> +}
> +
> static int ksz_ptp_settime(struct ptp_clock_info *ptp,
> const struct timespec64 *ts)
> {
[ ... ]
> @@ -1095,6 +1332,27 @@ static int ksz_ptp_start_clock(struct ksz_device *dev)
> return 0;
> }
>
> +void ksz8463_ptp_set_caps(struct dsa_switch *ds)
> +{
> + struct ksz_device *dev = ds->priv;
> + struct ksz_ptp_data *ptp_data;
> +
> + ptp_data = &dev->ptp_data;
> +
> + ptp_data->caps.owner = THIS_MODULE;
> + snprintf(ptp_data->caps.name, 16, "Microchip Clock");
> + ptp_data->caps.max_adj = KSZ_MAX_DRIFT_CORR;
> + ptp_data->caps.gettime64 = ksz_ptp_gettime;
> + ptp_data->caps.settime64 = ksz8463_ptp_settime;
> + ptp_data->caps.adjfine = ksz_ptp_adjfine;
> + ptp_data->caps.adjtime = ksz8463_ptp_adjtime;
> + ptp_data->caps.do_aux_work = ksz_ptp_do_aux_work;
> + ptp_data->caps.enable = ksz8463_ptp_enable;
> + ptp_data->caps.verify = ksz_ptp_verify_pin;
> + ptp_data->caps.n_pins = dev->info->n_pins;
> + ptp_data->caps.n_per_out = dev->info->n_per_out;
> +}
[Severity: Low]
This is a pre-existing omission rather than something this patch
introduces, but should supported_perout_flags be set here too?
The driver handles PTP_PEROUT_DUTY_CYCLE (ksz_ptp_get_pin() only rejects
"request->flags & ~PTP_PEROUT_DUTY_CYCLE", and
ksz_ptp_compute_perout_pulse() consumes request->on for it), yet
caps.supported_perout_flags is left at zero, and ptp_perout_request() does:
if (perout->flags & ~ops->supported_perout_flags)
return -EOPNOTSUPP;
so the duty-cycle branch cannot be reached from the UAPI. For the KSZ8463
in particular the maximum pulse width is 500 us, so the default 50 % duty
cycle is always clamped and the pulse width cannot be chosen at all. The
existing ksz_ptp_set_caps() has the same omission.
> void ksz_ptp_set_caps(struct dsa_switch *ds)
> {
> struct ksz_device *dev = ds->priv;
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260902-ksz-perout-v2-0-6f277fcc9e68%40bootlin.com
^ permalink raw reply [flat|nested] 14+ messages in thread