* [PATCH RFC net-next 00/20] Marvell PTP stuffs
@ 2025-09-18 17:38 Russell King (Oracle)
2025-09-18 17:38 ` [PATCH RFC net-next 01/20] ptp: marvell: add core support for Marvell PTP Russell King
` (19 more replies)
0 siblings, 20 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:38 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Not for merging, and, yes, it's more than 15 patches.
As the merge window is approaching, I thought I would share my current
state with the Marvell PTP library. I don't consider this ready for
merging yet, as I still have decisions to make on the structure for
multi-port setups such as DSA. 88E6165 support is also likely broken.
You will have noticed I've pushed out some patches cleaning up stuff
in the mv88e6xxx driver, and also making it easier for PTP clock
drivers to clean up when unregistering.
This series contains potentially another independent patch, adding
the ability to get the hwtstamp configuration from a MII timestamper,
although of course, the only known user right now is the Marvell PHY
PTP support (specifically 88E1510) in this series.
One of the things I don't like about the conversion for mv88e6xxx is
the "drop the old code, plug in the new". The hwtstamp.c changes
are split up, but they result in stuff becoming non-functional during
the transition.
The only thing I can think of doing to solve that is to forward the
hwtstamp_set() call to both implementations, and then convert the
tx side, rx side, and remove the old.
I've been running this for about 10 days (with reboots) between two
machines, one using the PHY side as the GM, and the other using
DSA as the slave. All seems happy, no timeouts on getting the
timestamps for the Sync or Delay_Req packets:
ptp4l[3032.775]: master offset -60 s2 freq -3984 path delay 11144
ptp4l[3033.775]: master offset -16 s2 freq -3958 path delay 11144
ptp4l[3034.775]: master offset 45 s2 freq -3901 path delay 11144
ptp4l[3035.775]: master offset 203 s2 freq -3730 path delay 11144
ptp4l[3036.775]: master offset 115 s2 freq -3757 path delay 11144
ptp4l[3037.775]: master offset -186 s2 freq -4023 path delay 11144
ptp4l[3038.775]: master offset -244 s2 freq -4137 path delay 11144
ptp4l[3039.775]: master offset -122 s2 freq -4088 path delay 11137
I've tested both L2 and L4 configurations. Whether I get these to
a point that I can post some of them for real next week is uncertain,
and I certainly won't post them unless I feel they are ready -
especially not before I'm happy with the library.
drivers/net/dsa/mv88e6xxx/Kconfig | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 10 +
drivers/net/dsa/mv88e6xxx/chip.h | 63 +--
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 664 ++++++++++++------------------
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 26 +-
drivers/net/dsa/mv88e6xxx/ptp.c | 527 +++++++++---------------
drivers/net/dsa/mv88e6xxx/ptp.h | 30 +-
drivers/net/phy/Kconfig | 13 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/marvell.c | 15 +-
drivers/net/phy/marvell_ptp.c | 369 +++++++++++++++++
drivers/net/phy/marvell_ptp.h | 17 +
drivers/net/phy/phy.c | 3 +
drivers/ptp/Kconfig | 4 +
drivers/ptp/Makefile | 2 +
drivers/ptp/ptp_marvell_tai.c | 445 ++++++++++++++++++++
drivers/ptp/ptp_marvell_ts.c | 778 +++++++++++++++++++++++++++++++++++
include/linux/marvell_ptp.h | 159 +++++++
include/linux/mii_timestamper.h | 3 +
19 files changed, 2318 insertions(+), 812 deletions(-)
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 01/20] ptp: marvell: add core support for Marvell PTP
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
@ 2025-09-18 17:38 ` Russell King
2025-09-18 17:39 ` [PATCH RFC net-next 02/20] net: phy: add hwtstamp_get() method for mii timestampers Russell King (Oracle)
` (18 subsequent siblings)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2025-09-18 17:38 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Provide core support for the Marvell PTP implementations, which
consist of a TAI (time application interface) and timestamping blocks.
This hardware can be found in Marvell 88E151x PHYs, Armada 38x and
Armada 37xx (mvneta), as well as Marvell DSA devices.
Support for both arrival timestamps is supported, we use arrival 1 for
PTP peer delay messages, and arrival 0 for all other messages, which
is the same as the Marvell DSA implementation.
External event capture is also supported.
PPS output and trigger generation is not supported.
This core takes inspiration from the existing Marvell 88E6xxx DSA PTP
code and DP83640 drivers. Like the original 88E6xxx DSA code, we
use a delayed work to keep the cycle counter updated, and a separate
delayed work for event capture.
We expose the ptp clock aux work to allow users to support single and
multi-port designs. A multi-port design will have a single Marvell TAI
instance and one Marvell TS instance per port.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/ptp/Kconfig | 4 +
drivers/ptp/Makefile | 2 +
drivers/ptp/ptp_marvell_tai.c | 445 +++++++++++++++++++
drivers/ptp/ptp_marvell_ts.c | 778 ++++++++++++++++++++++++++++++++++
include/linux/marvell_ptp.h | 159 +++++++
5 files changed, 1388 insertions(+)
create mode 100644 drivers/ptp/ptp_marvell_tai.c
create mode 100644 drivers/ptp/ptp_marvell_ts.c
create mode 100644 include/linux/marvell_ptp.h
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 5f8ea34d11d6..a01b1531d83e 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -184,6 +184,10 @@ config PTP_1588_CLOCK_FC3W
To compile this driver as a module, choose M here: the module
will be called ptp_fc3.
+config PTP_1588_CLOCK_MARVELL
+ tristate
+ depends on PTP_1588_CLOCK
+
config PTP_1588_CLOCK_MOCK
tristate "Mock-up PTP clock"
depends on PTP_1588_CLOCK
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index bdc47e284f14..0327a97a7277 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -12,6 +12,8 @@ obj-$(CONFIG_PTP_1588_CLOCK_INES) += ptp_ines.o
obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o
obj-$(CONFIG_PTP_1588_CLOCK_KVM) += ptp_kvm.o
obj-$(CONFIG_PTP_1588_CLOCK_VMCLOCK) += ptp_vmclock.o
+obj-$(CONFIG_PTP_1588_CLOCK_MARVELL) += ptp-marvell.o
+ptp-marvell-y := ptp_marvell_tai.o ptp_marvell_ts.o
obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp_qoriq.o
obj-$(CONFIG_PTP_1588_CLOCK_IDTCM) += ptp_clockmatrix.o
obj-$(CONFIG_PTP_1588_CLOCK_FC3W) += ptp_fc3.o
diff --git a/drivers/ptp/ptp_marvell_tai.c b/drivers/ptp/ptp_marvell_tai.c
new file mode 100644
index 000000000000..2802b72f54f1
--- /dev/null
+++ b/drivers/ptp/ptp_marvell_tai.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TAI (time application interface) driver for Marvell PHYs and Marvell NETA.
+ *
+ * This file implements TAI support as a PTP clock. Timecounter/cyclecounter
+ * representation taken from Marvell 88E6xxx DSA driver. We may need to share
+ * the TAI between multiple PHYs in a multiport PHY.
+ */
+#include <linux/if_ether.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+#include <linux/marvell_ptp.h>
+
+#define TAI_CONFIG_0 0
+#define TAI_CONFIG_0_EVENTCAPOV BIT(15)
+#define TAI_CONFIG_0_EVENTCTRSTART BIT(14)
+#define TAI_CONFIG_0_EVENTPHASE BIT(13)
+#define TAI_CONFIG_0_TRIGGENINTEN BIT(9)
+#define TAI_CONFIG_0_EVENTCAPINTEN BIT(8)
+
+/* TAI Global status register
+ * 15 EventInt (A38x, 88E151x) - Event capture interrupt
+ * 14 Capture (88E6393) - Capture trigger (0=extts 1=PTP_TRIG internal event)
+ * 9 EventCapErr - Event capture error (overflow)
+ * 8 EventCapValid - Event capture valid
+ * 7:0 EventCapCtr - Event capture counter
+ */
+#define TAI_CONFIG_9 9
+#define TAI_CONFIG_9_EVENTCAPERR BIT(9)
+#define TAI_CONFIG_9_EVENTCAPVALID BIT(8)
+
+#define TAI_EVENT_POLL_INTERVAL msecs_to_jiffies(100)
+
+struct marvell_tai {
+ const struct marvell_tai_ops *ops;
+ struct device *dev;
+
+ struct ptp_clock_info caps;
+ struct ptp_clock *ptp_clock;
+
+ u32 cc_mult_num;
+ u32 cc_mult_den;
+ u32 cc_mult;
+
+ struct mutex mutex;
+ struct timecounter timecounter;
+ struct cyclecounter cyclecounter;
+
+ long half_overflow_period;
+ struct delayed_work overflow_work;
+ struct delayed_work event_work;
+
+ /* Used while reading the TAI */
+ struct ptp_system_timestamp *sts;
+};
+
+static struct marvell_tai *cc_to_tai(struct cyclecounter *cc)
+{
+ return container_of(cc, struct marvell_tai, cyclecounter);
+}
+
+/* Read the global time registers using the readplus command */
+static u64 marvell_tai_clock_read(struct cyclecounter *cc)
+{
+ struct marvell_tai *tai = cc_to_tai(cc);
+
+ return tai->ops->tai_clock_read(tai->dev, tai->sts);
+}
+
+u64 marvell_tai_cyc2time(struct marvell_tai *tai, u32 cyc)
+{
+ u64 ns;
+
+ mutex_lock(&tai->mutex);
+ ns = timecounter_cyc2time(&tai->timecounter, cyc);
+ mutex_unlock(&tai->mutex);
+
+ return ns;
+}
+EXPORT_SYMBOL_GPL(marvell_tai_cyc2time);
+
+static struct marvell_tai *ptp_to_tai(struct ptp_clock_info *ptp)
+{
+ return container_of(ptp, struct marvell_tai, caps);
+}
+
+static int marvell_tai_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct marvell_tai *tai = ptp_to_tai(ptp);
+ bool neg;
+ u32 diff;
+ u64 adj;
+
+ neg = scaled_ppm < 0;
+ if (neg)
+ scaled_ppm = -scaled_ppm;
+
+ adj = tai->cc_mult_num;
+ adj *= scaled_ppm;
+ diff = div_u64(adj, tai->cc_mult_den);
+
+ mutex_lock(&tai->mutex);
+ timecounter_read(&tai->timecounter);
+ tai->cyclecounter.mult = neg ? tai->cc_mult - diff :
+ tai->cc_mult + diff;
+ mutex_unlock(&tai->mutex);
+
+ return 0;
+}
+
+static int marvell_tai_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct marvell_tai *tai = ptp_to_tai(ptp);
+
+ mutex_lock(&tai->mutex);
+ timecounter_adjtime(&tai->timecounter, delta);
+ mutex_unlock(&tai->mutex);
+
+ return 0;
+}
+
+static int marvell_tai_gettimex64(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct marvell_tai *tai = ptp_to_tai(ptp);
+ u64 ns;
+
+ mutex_lock(&tai->mutex);
+ tai->sts = sts;
+ ns = timecounter_read(&tai->timecounter);
+ tai->sts = NULL;
+ mutex_unlock(&tai->mutex);
+
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+static int marvell_tai_settime64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct marvell_tai *tai = ptp_to_tai(ptp);
+ u64 ns = timespec64_to_ns(ts);
+
+ mutex_lock(&tai->mutex);
+ timecounter_init(&tai->timecounter, &tai->cyclecounter, ns);
+ mutex_unlock(&tai->mutex);
+
+ return 0;
+}
+
+static void marvell_tai_extts(struct marvell_tai *tai)
+{
+ struct marvell_extts extts;
+ struct ptp_clock_event ev;
+ int err;
+
+ err = tai->ops->tai_extts_read(tai->dev, TAI_CONFIG_9, &extts);
+ if (err < 0) {
+ dev_err(tai->dev, "failed to read TAI event capture\n");
+ return;
+ }
+
+ if (extts.status & TAI_CONFIG_9_EVENTCAPERR) {
+ dev_warn(tai->dev, "extts timestamp overrun (%x)\n",
+ extts.status);
+ return;
+ }
+
+ if (extts.status & TAI_CONFIG_9_EVENTCAPVALID) {
+ ev.type = PTP_CLOCK_EXTTS;
+ ev.index = 0;
+ ev.timestamp = marvell_tai_cyc2time(tai, extts.time);
+
+ ptp_clock_event(tai->ptp_clock, &ev);
+ }
+}
+
+static int marvell_tai_enable_extts(struct marvell_tai *tai,
+ struct ptp_extts_request *req, int enable)
+{
+ int err, pin;
+ u16 cfg0;
+
+ /* Reject requests to enable timestamping on both edges if
+ * userspace requests strict mode.
+ */
+ if (req->flags & PTP_ENABLE_FEATURE &&
+ req->flags & PTP_STRICT_FLAGS &&
+ (req->flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES)
+ return -EINVAL;
+
+ pin = ptp_find_pin(tai->ptp_clock, PTP_PF_EXTTS, req->index);
+ if (pin < 0)
+ return -EBUSY;
+
+ /* Setup this pin */
+ err = tai->ops->tai_pin_setup(tai->dev, pin, PTP_PF_EXTTS, enable);
+ if (err < 0)
+ return err;
+
+ if (enable) {
+ /* Clear the status */
+ err = tai->ops->tai_write(tai->dev, TAI_CONFIG_9, 0);
+ if (err < 0)
+ return err;
+
+ cfg0 = TAI_CONFIG_0_EVENTCAPINTEN |
+ TAI_CONFIG_0_EVENTCTRSTART;
+
+ /*
+ * For compatibility with DSA, we test for !rising rather
+ * than for falling. Marvell PHYs (88E151x) doesn't have
+ * this.
+ */
+ if (!(req->flags & PTP_RISING_EDGE))
+ cfg0 |= TAI_CONFIG_0_EVENTPHASE;
+
+ /* Enable the event interrupt and counter */
+ err = tai->ops->tai_modify(tai->dev, TAI_CONFIG_0,
+ TAI_CONFIG_0_EVENTCAPOV |
+ TAI_CONFIG_0_EVENTCTRSTART |
+ TAI_CONFIG_0_EVENTCAPINTEN |
+ TAI_CONFIG_0_EVENTPHASE, cfg0);
+ if (err < 0)
+ return err;
+
+ schedule_delayed_work(&tai->event_work,
+ TAI_EVENT_POLL_INTERVAL);
+ } else {
+ /* Disable the event interrupt and counter */
+ err = tai->ops->tai_modify(tai->dev, TAI_CONFIG_0,
+ TAI_CONFIG_0_EVENTCTRSTART |
+ TAI_CONFIG_0_EVENTCAPINTEN, 0);
+ if (err < 0)
+ return err;
+
+ cancel_delayed_work_sync(&tai->event_work);
+ }
+
+ return 0;
+}
+
+static int marvell_tai_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *req, int enable)
+{
+ if (req->type != PTP_CLK_REQ_EXTTS)
+ return -EOPNOTSUPP;
+
+ return marvell_tai_enable_extts(ptp_to_tai(ptp), &req->extts, enable);
+}
+
+static int marvell_tai_verify(struct ptp_clock_info *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ struct marvell_tai *tai = ptp_to_tai(ptp);
+
+ /* Always allow a pin to be set to no function */
+ if (func == PTP_PF_NONE)
+ return 0;
+
+ /* This driver only supports PTP_PF_EXTTS */
+ if (func != PTP_PF_EXTTS)
+ return -EOPNOTSUPP;
+
+ if (!tai->ops->tai_pin_verify)
+ return -EOPNOTSUPP;
+
+ return tai->ops->tai_pin_verify(tai->dev, pin, func, chan);
+}
+
+static long marvell_tai_aux_work(struct ptp_clock_info *ptp)
+{
+ struct marvell_tai *tai = ptp_to_tai(ptp);
+ long ret = -1;
+
+ if (tai->ops->tai_aux_work)
+ ret = tai->ops->tai_aux_work(tai->dev);
+
+ return ret;
+}
+
+#define event_work_to_tai(w) \
+ container_of(to_delayed_work(w), struct marvell_tai, event_work)
+static void marvell_tai_event_work(struct work_struct *w)
+{
+ struct marvell_tai *tai = event_work_to_tai(w);
+
+ marvell_tai_extts(tai);
+
+ schedule_delayed_work(&tai->event_work, TAI_EVENT_POLL_INTERVAL);
+}
+
+/* Periodically read the timecounter to keep the time refreshed. */
+#define overflow_work_to_tai(w) \
+ container_of(to_delayed_work(w), struct marvell_tai, overflow_work)
+static void marvell_tai_overflow_work(struct work_struct *w)
+{
+ struct marvell_tai *tai = overflow_work_to_tai(w);
+
+ /* Read the timecounter to update */
+ mutex_lock(&tai->mutex);
+ timecounter_read(&tai->timecounter);
+ mutex_unlock(&tai->mutex);
+
+ schedule_delayed_work(&tai->overflow_work, tai->half_overflow_period);
+}
+
+static int marvell_tai_hw_enable(struct marvell_tai *tai)
+{
+ return tai->ops->tai_hw_enable(tai->dev);
+}
+
+static void marvell_tai_hw_disable(struct marvell_tai *tai)
+{
+ tai->ops->tai_hw_disable(tai->dev);
+}
+
+int marvell_tai_ptp_clock_index(struct marvell_tai *tai)
+{
+ return ptp_clock_index(tai->ptp_clock);
+}
+EXPORT_SYMBOL_GPL(marvell_tai_ptp_clock_index);
+
+int marvell_tai_schedule(struct marvell_tai *tai, unsigned long delay)
+{
+ return ptp_schedule_worker(tai->ptp_clock, delay);
+}
+EXPORT_SYMBOL_GPL(marvell_tai_schedule);
+
+void marvell_tai_remove(struct marvell_tai *tai)
+{
+ ptp_clock_unregister(tai->ptp_clock);
+
+ /* tai->event_work will be disabled by ptp_clock_unregister()
+ * disabling the pins, so there's no need call
+ * cancel_delayed_work_sync(&tai->event_work) here.
+ */
+
+ cancel_delayed_work_sync(&tai->overflow_work);
+
+ marvell_tai_hw_disable(tai);
+}
+EXPORT_SYMBOL_GPL(marvell_tai_remove);
+
+int marvell_tai_probe(struct marvell_tai **taip,
+ const struct marvell_tai_ops *ops,
+ const struct marvell_tai_param *param,
+ const struct marvell_tai_pins *pins,
+ const char *name, struct device *dev)
+{
+ struct marvell_tai *tai;
+ u64 overflow_ns;
+ int err;
+
+ tai = devm_kzalloc(dev, sizeof(*tai), GFP_KERNEL);
+ if (!tai)
+ return -ENOMEM;
+
+ mutex_init(&tai->mutex);
+
+ tai->dev = dev;
+ tai->ops = ops;
+ tai->cc_mult_num = param->cc_mult_num;
+ tai->cc_mult_den = param->cc_mult_den;
+ tai->cc_mult = param->cc_mult;
+
+ err = marvell_tai_hw_enable(tai);
+ if (err < 0)
+ return err;
+
+ tai->cyclecounter.read = marvell_tai_clock_read;
+ tai->cyclecounter.mask = CYCLECOUNTER_MASK(32);
+ tai->cyclecounter.mult = param->cc_mult;
+ tai->cyclecounter.shift = param->cc_shift;
+
+ overflow_ns = BIT_ULL(32) * param->cc_mult;
+ overflow_ns >>= param->cc_shift;
+ tai->half_overflow_period = nsecs_to_jiffies64(overflow_ns / 2);
+
+ timecounter_init(&tai->timecounter, &tai->cyclecounter,
+ ktime_to_ns(ktime_get_real()));
+
+ tai->caps.owner = THIS_MODULE;
+ strscpy(tai->caps.name, name, sizeof(tai->caps.name));
+ /* max_adj of 1000000 is what MV88E6xxx DSA uses */
+ tai->caps.max_adj = 1000000;
+ tai->caps.adjfine = marvell_tai_adjfine;
+ tai->caps.adjtime = marvell_tai_adjtime;
+ tai->caps.gettimex64 = marvell_tai_gettimex64;
+ tai->caps.settime64 = marvell_tai_settime64;
+ tai->caps.do_aux_work = marvell_tai_aux_work;
+
+ if (pins) {
+ tai->caps.n_ext_ts = pins->n_ext_ts;
+ tai->caps.n_pins = pins->n_pins;
+ tai->caps.pin_config = pins->pins;
+ tai->caps.enable = marvell_tai_enable;
+ tai->caps.verify = marvell_tai_verify;
+
+ tai->caps.supported_extts_flags = PTP_STRICT_FLAGS |
+ pins->supported_extts_flags;
+ }
+
+ INIT_DELAYED_WORK(&tai->overflow_work, marvell_tai_overflow_work);
+ INIT_DELAYED_WORK(&tai->event_work, marvell_tai_event_work);
+
+ tai->ptp_clock = ptp_clock_register(&tai->caps, dev);
+ if (IS_ERR(tai->ptp_clock)) {
+ marvell_tai_hw_disable(tai);
+ return PTR_ERR(tai->ptp_clock);
+ }
+
+ /*
+ * Kick off the auxiliary worker to run once every half-overflow
+ * period to keep the timecounter properly updated.
+ */
+ schedule_delayed_work(&tai->overflow_work, tai->half_overflow_period);
+
+ *taip = tai;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(marvell_tai_probe);
+
+static void marvell_tai_devm_remove(void *data)
+{
+ marvell_tai_remove(data);
+}
+
+int devm_marvell_tai_probe(struct marvell_tai **taip,
+ const struct marvell_tai_ops *ops,
+ const struct marvell_tai_param *param,
+ const struct marvell_tai_pins *pins,
+ const char *name, struct device *dev)
+{
+ int ret = marvell_tai_probe(taip, ops, param, pins, name, dev);
+
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, marvell_tai_devm_remove, *taip);
+}
+EXPORT_SYMBOL_GPL(devm_marvell_tai_probe);
diff --git a/drivers/ptp/ptp_marvell_ts.c b/drivers/ptp/ptp_marvell_ts.c
new file mode 100644
index 000000000000..46c82d4a490d
--- /dev/null
+++ b/drivers/ptp/ptp_marvell_ts.c
@@ -0,0 +1,778 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Marvell PTP driver for 88E1510, 88E1512, 88E1514 and 88E1518 PHYs
+ *
+ * Ideas taken from 88E6xxx DSA and DP83640 drivers. This file
+ * implements the packet timestamping support only (PTP). TAI
+ * support is separate.
+ */
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/interrupt.h>
+#include <linux/marvell_ptp.h>
+#include <linux/netdevice.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/uaccess.h>
+
+/* Global configuration */
+
+/* This defines which incoming or outgoing PTP frames are timestamped.
+ * MV88E6xxx DSA sets messages types 0-3 (sync, delay request, pdelay
+ * request and pdelay response.)
+ *
+ * We need to timestamp `t1' the departure of Sync (0) messages so that
+ * timestamp can be sent in the Follow_Up message. We also need to
+ * timestamp the arrival of these messages to give `t2'.
+ *
+ * We need to timestamp the transmission of the Delay_Req (1) messages
+ * for `t3' and the arrival of this mssage for `t4'.
+ *
+ * For IEEE1588 v2, we also need to timestamp the PDelay_Req (3) and
+ * PDelay_Resp (4) messages.
+ *
+ * The Follow_Up (8) and Delay_Resp (9) messages do not need to be
+ * timestamped.
+ *
+ * PTP_MSGTYPE_PDELAY_REQ, PTP_MSGTYPE_PDELAY_RESP
+ */
+#define MV_PTP_MSD_ID_TS_EN (BIT(PTP_MSGTYPE_SYNC) | \
+ BIT(PTP_MSGTYPE_DELAY_REQ) | \
+ BIT(PTP_MSGTYPE_PDELAY_REQ) | \
+ BIT(PTP_MSGTYPE_PDELAY_RESP))
+
+/* Direct Sync messages to Arr0 and delay messages to Arr1. MV88E6xxx
+ * DSA sets message type 3 (pdelay response.)
+ *
+ * Putting Delay_Req (1) arrival into Arr1 means that if we have a busy
+ * network with Sync (0) messages also being received, we still get a
+ * hardware timestamp for the Delay_Req message.
+ *
+ * PTP_MSGTYPE_PDELAY_RESP
+ */
+#define MV_PTP_TS_ARR_PTR (BIT(PTP_MSGTYPE_DELAY_REQ) | \
+ BIT(PTP_MSGTYPE_PDELAY_RESP))
+
+/* Armada 38x and 88e151x calls this PTP Global Configuration 0:
+ * 15:0 PTPEType - Ethernet type
+ */
+#define PTPG_ETYPE 0
+
+/* Armada 38x and 88e151x calls this PTP Global Configuration1
+ * 15:0 MsgIDTSEn - Message Identifier Time Stamp Enable
+ * 15:0 MsgType (88E6393x) Message Type Time Stamp Enable
+ */
+#define PTPG_MSGIDTSEN 1
+
+/* Armada 38x and 88e151x calls this PTP Global Configuration2
+ * 15:0 TSArrPtr - Time Stamp Arrival Time Pointer
+ */
+#define PTPG_TSARRPTR 2
+
+/* Armada 38x calls this PTP Global Status0. 88E151x "PTP Global Status".
+ * Armada 38x: 5:0 PTPInt - Port interrupt
+ * 88E151x : 0: PTPInt - Interrupt
+ */
+#define PTPG_STATUS 8
+
+#define TX_TIMEOUT_MS 40
+#define RX_TIMEOUT_MS 40
+
+#define PTP_PORT_CONFIG_0 0
+#define PTP_PORT_CONFIG_0_DISTSPECCHECK BIT(11)
+#define PTP_PORT_CONFIG_0_DISTSOVERWRITE BIT(1)
+#define PTP_PORT_CONFIG_0_DISPTP BIT(0)
+#define PTP_PORT_CONFIG_1 1
+#define PTP_PORT_CONFIG_1_IPJUMP GENMASK(13, 8)
+#define PTP_PORT_CONFIG_1_ETJUMP GENMASK(4, 0)
+#define PTP_PORT_CONFIG_2 2
+#define PTP_PORT_CONFIG_2_DEPINTEN BIT(1)
+#define PTP_PORT_CONFIG_2_ARRINTEN BIT(0)
+
+struct marvell_ts_cb {
+ const struct ptp_header *hdr;
+ unsigned long timeout;
+ u16 seq;
+};
+#define MARVELL_TS_CB(skb) ((struct marvell_ts_cb *)(skb)->cb)
+
+/* RX queue support */
+
+/* Deliver a skb with its timestamp back to the networking core */
+static void marvell_rxq_rx(struct sk_buff *skb, u64 ns)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+
+ pr_debug("rx: seq %u delivering timestamp\n", MARVELL_TS_CB(skb)->seq);
+
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ns);
+ netif_rx(skb);
+}
+
+/* Get a rx timestamp entry. Try the free list, and if that fails,
+ * steal the oldest off the pending list.
+ */
+static struct marvell_rxts *marvell_rxq_get_rxts(struct marvell_rxq *rxq)
+{
+ if (!list_empty(&rxq->rx_free))
+ return list_first_entry(&rxq->rx_free, struct marvell_rxts,
+ node);
+
+ return list_last_entry(&rxq->rx_pend, struct marvell_rxts, node);
+}
+
+static void marvell_rxq_init(struct marvell_rxq *rxq)
+{
+ int i;
+
+ mutex_init(&rxq->rx_mutex);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_pend);
+ skb_queue_head_init(&rxq->rx_queue);
+
+ for (i = 0; i < ARRAY_SIZE(rxq->rx_ts); i++)
+ list_add_tail(&rxq->rx_ts[i].node, &rxq->rx_free);
+}
+
+static void marvell_rxq_purge(struct marvell_rxq *rxq)
+{
+ skb_queue_purge(&rxq->rx_queue);
+}
+
+static void marvell_rxq_rx_ts(struct marvell_rxq *rxq, u16 seq, u64 ns)
+{
+ struct marvell_rxts *rxts;
+ struct sk_buff *skb;
+ bool found = false;
+
+ mutex_lock(&rxq->rx_mutex);
+
+ /* Search the rx queue for a matching skb */
+ skb_queue_walk(&rxq->rx_queue, skb) {
+ if (MARVELL_TS_CB(skb)->seq == seq) {
+ __skb_unlink(skb, &rxq->rx_queue);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_debug("rx: seq %u skb not found, pending\n", seq);
+
+ rxts = marvell_rxq_get_rxts(rxq);
+ rxts->ns = ns;
+ rxts->seq = seq;
+ list_move(&rxts->node, &rxq->rx_pend);
+ }
+
+ mutex_unlock(&rxq->rx_mutex);
+
+ if (found)
+ marvell_rxq_rx(skb, ns);
+}
+
+static bool marvell_rxq_rxtstamp(struct marvell_rxq *rxq, struct sk_buff *skb,
+ u16 seq, const struct ptp_header *hdr)
+{
+ struct marvell_rxts *rxts;
+ bool found = false;
+ u64 ns;
+
+ mutex_lock(&rxq->rx_mutex);
+
+ /* Search the pending receive timestamps for a matching seqid */
+ list_for_each_entry(rxts, &rxq->rx_pend, node) {
+ if (rxts->seq == seq) {
+ found = true;
+ ns = rxts->ns;
+ /* Move this timestamp entry to the free list */
+ list_move_tail(&rxts->node, &rxq->rx_free);
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_debug("rx: seq %u pending ts not found, queueing\n", seq);
+
+ /* Store the seqid and queue the skb. Do this under the lock
+ * to ensure we don't miss any timestamps appended to the
+ * rx_pend list.
+ */
+ MARVELL_TS_CB(skb)->hdr = hdr;
+ MARVELL_TS_CB(skb)->seq = seq;
+ MARVELL_TS_CB(skb)->timeout = jiffies +
+ msecs_to_jiffies(RX_TIMEOUT_MS);
+ __skb_queue_tail(&rxq->rx_queue, skb);
+ }
+
+ mutex_unlock(&rxq->rx_mutex);
+
+ if (found)
+ /* We found the corresponding timestamp. If we can add the
+ * timestamp, do we need to go through the netif_rx_ni()
+ * path, or would it be more efficient to add the timestamp
+ * and return "false" from marvell_ts_rxtstamp() instead?
+ */
+ marvell_rxq_rx(skb, ns);
+
+ return found;
+}
+
+static void marvell_rxq_expire(struct marvell_rxq *rxq,
+ struct sk_buff_head *list)
+{
+ struct sk_buff *skb;
+
+ mutex_lock(&rxq->rx_mutex);
+ while ((skb = skb_dequeue(&rxq->rx_queue)) != NULL) {
+ if (!time_is_before_jiffies(MARVELL_TS_CB(skb)->timeout)) {
+ __skb_queue_head(&rxq->rx_queue, skb);
+ break;
+ }
+ __skb_queue_tail(list, skb);
+ }
+ mutex_unlock(&rxq->rx_mutex);
+}
+
+/* Extract the sequence ID */
+static u16 ptp_seqid(const struct ptp_header *ptp_hdr)
+{
+ const __be16 *seqp = &ptp_hdr->sequence_id;
+
+ return be16_to_cpup(seqp);
+}
+
+static u8 ptp_msgid(const struct ptp_header *ptp_hdr)
+{
+ return ptp_hdr->tsmt & 15;
+}
+
+static void marvell_ts_schedule(struct marvell_ts *ts)
+{
+ marvell_tai_schedule(ts->tai, 0);
+}
+
+/* Check for a rx timestamp entry, try to find the corresponding skb and
+ * deliver it, otherwise add the rx timestamp to the queue of pending
+ * timestamps.
+ */
+static int marvell_ts_rx_ts(struct marvell_ts *ts, int q)
+{
+ enum marvell_ts_reg reg;
+ struct marvell_hwts hwts;
+ int err;
+ u64 ns;
+
+ if (q)
+ reg = MARVELL_TS_ARR1;
+ else
+ reg = MARVELL_TS_ARR0;
+
+ err = ts->ops->ts_port_read_ts(ts->dev, &hwts, ts->port, reg);
+ dev_dbg(ts->dev, "p%uq%u: rx: read_ts %d\n", ts->port, q, err);
+ if (err <= 0)
+ return 0;
+
+ dev_dbg(ts->dev, "p%uq%u: tx: stat=0x%x seq=%u ts=%u\n",
+ ts->port, q, hwts.stat, hwts.seq, hwts.time);
+
+ if ((hwts.stat & MV_STATUS_INTSTATUS_MASK) !=
+ MV_STATUS_INTSTATUS_NORMAL)
+ dev_warn(ts->dev,
+ "p%uq%u: rx: timestamp overrun (stat=0x%x seq=%u)\n",
+ ts->port, q, hwts.stat, hwts.seq);
+
+ ns = marvell_tai_cyc2time(ts->tai, hwts.time);
+
+ marvell_rxq_rx_ts(&ts->rxq[q], hwts.seq, ns);
+
+ return 1;
+}
+
+/* Check whether the packet is suitable for timestamping, and if so,
+ * try to find a pending timestamp for it. If no timestamp is found,
+ * queue the packet with a timeout.
+ */
+bool marvell_ts_rxtstamp(struct marvell_ts *ts, struct sk_buff *skb, int type)
+{
+ const struct ptp_header *ptp_hdr;
+ u16 msgidvec, seq;
+ unsigned int q;
+ u8 msgid;
+
+ if (ts->rx_filter == HWTSTAMP_FILTER_NONE)
+ return false;
+
+ ptp_hdr = ptp_parse_header(skb, type);
+ if (!ptp_hdr)
+ return false;
+
+ msgid = ptp_msgid(ptp_hdr);
+ seq = ptp_seqid(ptp_hdr);
+
+ /* Only check for timestamps for PTP packets whose message ID value
+ * is one that we are capturing timestamps for. This is part of the
+ * global configuration and is therefore fixed.
+ */
+ msgidvec = BIT(msgid);
+ if (msgidvec & ~MV_PTP_MSD_ID_TS_EN) {
+ dev_dbg(ts->dev, "p%u: rx: not timestamping msgid %u seq %u\n",
+ ts->port, msgid, seq);
+ return false;
+ }
+
+ /* Determine the queue which the timestamp for this message ID will
+ * appear. This is part of the global configuration and is therefore
+ * fixed.
+ */
+ q = !!(msgidvec & MV_PTP_TS_ARR_PTR);
+
+ dev_dbg(ts->dev, "p%uq%u: rx: timestamping msgid %u seq %u\n",
+ ts->port, q, msgid, seq);
+
+ if (!marvell_rxq_rxtstamp(&ts->rxq[q], skb, seq, ptp_hdr))
+ marvell_ts_schedule(ts);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_rxtstamp);
+
+/* Move any expired skbs on to our own list, and then hand the contents of
+ * our list to netif_rx() - this avoids calling netif_rx() with our
+ * mutex held.
+ */
+static void marvell_ts_rx_expire(struct marvell_ts *ts)
+{
+ const struct ptp_header *ptp_hdr;
+ struct sk_buff_head list;
+ struct sk_buff *skb;
+ int i;
+
+ __skb_queue_head_init(&list);
+
+ for (i = 0; i < ARRAY_SIZE(ts->rxq); i++)
+ marvell_rxq_expire(&ts->rxq[i], &list);
+
+ while ((skb = __skb_dequeue(&list)) != NULL) {
+ ptp_hdr = MARVELL_TS_CB(skb)->hdr;
+ dev_warn(ts->dev, "p%u: rx: expiring skb: seq=%u msgid=%u\n",
+ ts->port, MARVELL_TS_CB(skb)->seq,
+ ptp_msgid(ptp_hdr));
+ netif_rx(skb);
+ }
+}
+
+/* Complete the transmit timestamping; this is called to read the transmit
+ * timestamp from the PHY, and report back the transmitted timestamp.
+ */
+static int marvell_ts_txtstamp_complete(struct marvell_ts *ts)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct sk_buff *skb = ts->tx_skb;
+ struct marvell_hwts hwts;
+ int err;
+ u64 ns;
+
+ err = ts->ops->ts_port_read_ts(ts->dev, &hwts, ts->port,
+ MARVELL_TS_DEP);
+ dev_dbg(ts->dev, "p%u: tx: read_ts %d\n", ts->port, err);
+ if (err < 0)
+ goto fail;
+
+ if (err == 0) {
+ if (time_is_before_jiffies(MARVELL_TS_CB(skb)->timeout)) {
+ dev_warn(ts->dev, "p%u: tx: timestamp timeout\n",
+ ts->port);
+ goto free;
+ }
+ return 0;
+ }
+
+ dev_dbg(ts->dev, "p%u: tx: stat=0x%x seq=%u ts=%u\n", ts->port,
+ hwts.stat, hwts.seq, hwts.time);
+
+ /* Check the status */
+ if ((hwts.stat & MV_STATUS_INTSTATUS_MASK) !=
+ MV_STATUS_INTSTATUS_NORMAL) {
+ dev_warn(ts->dev,
+ "p%u: tx: timestamp overrun (stat=0x%x seq=%u)\n",
+ ts->port, hwts.stat, hwts.seq);
+ goto free;
+ }
+
+ /* Reject if the sequence number doesn't match */
+ if (hwts.seq != MARVELL_TS_CB(skb)->seq) {
+ dev_warn(ts->dev,
+ "p%u: tx: timestamp unexpected sequence id\n",
+ ts->port);
+ goto free;
+ }
+
+ ts->tx_skb = NULL;
+
+ /* Set the timestamp */
+ ns = marvell_tai_cyc2time(ts->tai, hwts.time);
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ns_to_ktime(ns);
+ skb_complete_tx_timestamp(skb, &shhwtstamps);
+ return 1;
+
+fail:
+ dev_err_ratelimited(ts->dev, "p%u: failed reading PTP: %pe\n",
+ ts->port, ERR_PTR(err));
+free:
+ dev_kfree_skb_any(skb);
+ ts->tx_skb = NULL;
+ return -1;
+}
+
+/* Check whether the skb will be timestamped on transmit; we only support
+ * a single outstanding skb. Add it if the slot is available. It is the
+ * responsibility of the caller to check tx_flags.
+ */
+bool marvell_ts_txtstamp(struct marvell_ts *ts, struct sk_buff *skb, int type)
+{
+ const struct ptp_header *ptp_hdr;
+ u8 msgid;
+
+ if (ts->tx_type != HWTSTAMP_TX_ON)
+ return false;
+
+ ptp_hdr = ptp_parse_header(skb, type);
+ if (!ptp_hdr)
+ return false;
+
+ msgid = ptp_msgid(ptp_hdr);
+ if (BIT(msgid) & ~MV_PTP_MSD_ID_TS_EN) {
+ dev_dbg(ts->dev, "p%u: tx: not timestamping msgid %u seq %u\n",
+ ts->port, msgid, ptp_seqid(ptp_hdr));
+ return false;
+ }
+
+ MARVELL_TS_CB(skb)->seq = ptp_seqid(ptp_hdr);
+ MARVELL_TS_CB(skb)->timeout = jiffies +
+ msecs_to_jiffies(TX_TIMEOUT_MS);
+
+ dev_dbg(ts->dev, "p%u: tx: new, msgid=%u seq=%u\n", ts->port,
+ msgid, MARVELL_TS_CB(skb)->seq);
+
+ if (cmpxchg(&ts->tx_skb, NULL, skb) != NULL)
+ return false;
+
+ /* DP83640 marks the skb for hw timestamping. Since the MAC driver
+ * may call skb_tx_timestamp() but may not support timestamping
+ * itself, it may not set this flag. So, we need to do this here.
+ */
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
+ /* Only schedule the aux_work if we haven't seen an interrupt. */
+ if (!ts->irq_handler_called)
+ marvell_ts_schedule(ts);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_txtstamp);
+
+int marvell_ts_hwtstamp_get(struct marvell_ts *ts,
+ struct kernel_hwtstamp_config *kcfg)
+{
+ kcfg->flags = 0;
+ kcfg->tx_type = ts->tx_type;
+ kcfg->rx_filter = ts->rx_filter;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_hwtstamp_get);
+
+int marvell_ts_hwtstamp_set(struct marvell_ts *ts,
+ struct kernel_hwtstamp_config *kcfg,
+ struct netlink_ext_ack *ack)
+{
+ u16 cfg0 = PTP_PORT_CONFIG_0_DISPTP;
+ bool enabled = false;
+ bool old_enabled;
+ u16 cfg2 = 0;
+ int err;
+
+ if (kcfg->flags)
+ return -EINVAL;
+
+ switch (kcfg->tx_type) {
+ case HWTSTAMP_TX_OFF:
+ break;
+
+ case HWTSTAMP_TX_ON:
+ cfg0 = 0;
+ cfg2 |= PTP_PORT_CONFIG_2_DEPINTEN;
+ enabled = true;
+ break;
+
+ default:
+ return -ERANGE;
+ }
+
+ switch (kcfg->rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+
+ /* UDPv4/IP PTP v2*/
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+
+ /* 802.1AS PTP v2 */
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+
+ /* 802.1AS and/or UDPv4/IP PTP v2 */
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ /* We accept 802.1AS, IEEE 1588v1 and IEEE 1588v2. We could
+ * filter on 802.1AS using the transportSpecific field, but
+ * that affects the transmit path too.
+ */
+ kcfg->rx_filter = HWTSTAMP_FILTER_SOME;
+ cfg0 = 0;
+ cfg2 |= PTP_PORT_CONFIG_2_ARRINTEN;
+ enabled = true;
+ break;
+
+ default:
+ return -ERANGE;
+ }
+
+ old_enabled = ts->tx_type != HWTSTAMP_TX_OFF ||
+ ts->rx_filter != HWTSTAMP_FILTER_NONE;
+ if (ts->ops->ts_port_enable && enabled && !old_enabled) {
+ err = ts->ops->ts_port_enable(ts->dev, ts->port);
+ if (err)
+ return err;
+ }
+
+ err = ts->ops->ts_port_modify(ts->dev, ts->port, PTP_PORT_CONFIG_0,
+ PTP_PORT_CONFIG_0_DISPTP, cfg0);
+ if (err)
+ return err;
+
+ err = ts->ops->ts_port_write(ts->dev, ts->port, PTP_PORT_CONFIG_2,
+ cfg2);
+ if (err)
+ return err;
+
+ if (ts->ops->ts_port_disable && !enabled && old_enabled)
+ ts->ops->ts_port_disable(ts->dev, ts->port);
+
+ ts->tx_type = kcfg->tx_type;
+ ts->rx_filter = kcfg->rx_filter;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_hwtstamp_set);
+
+int marvell_ts_info(struct marvell_ts *ts,
+ struct kernel_ethtool_ts_info *ts_info)
+{
+ if (!ts->tai)
+ return 0;
+
+ ts_info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ ts_info->phc_index = marvell_tai_ptp_clock_index(ts->tai);
+
+ ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) |
+ BIT(HWTSTAMP_TX_ON);
+
+ ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+ ts->caps->rx_filters;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_info);
+
+static int marvell_ts_port_config(struct marvell_ts *ts)
+{
+ const struct marvell_ts_ops *ops = ts->ops;
+ int err;
+
+ /* Disable transport specific check (if the PTP common header)
+ * Disable timestamp overwriting (so we can read a stable entry.)
+ * Disable PTP
+ */
+ err = ops->ts_port_write(ts->dev, ts->port, PTP_PORT_CONFIG_0,
+ PTP_PORT_CONFIG_0_DISTSPECCHECK |
+ PTP_PORT_CONFIG_0_DISTSOVERWRITE |
+ PTP_PORT_CONFIG_0_DISPTP);
+ if (err < 0)
+ return err;
+
+ /* Set ether-type jump to 12 (to ether protocol)
+ * Set IP jump to 2 (to skip over ether protocol)
+ * Does this mean it won't pick up on VLAN packets?
+ */
+ err = ops->ts_port_write(ts->dev, ts->port, PTP_PORT_CONFIG_1,
+ FIELD_PREP(PTP_PORT_CONFIG_1_IPJUMP, 2) |
+ FIELD_PREP(PTP_PORT_CONFIG_1_ETJUMP, 12));
+ if (err < 0)
+ return err;
+
+ /* Disable all interrupts */
+ ops->ts_port_write(ts->dev, ts->port, PTP_PORT_CONFIG_2, 0);
+
+ return 0;
+}
+
+static void marvell_ts_port_disable(struct marvell_ts *ts)
+{
+ /* Disable PTP */
+ ts->ops->ts_port_write(ts->dev, ts->port, PTP_PORT_CONFIG_0,
+ PTP_PORT_CONFIG_0_DISPTP);
+
+ /* Disable interrupts */
+ ts->ops->ts_port_write(ts->dev, ts->port, PTP_PORT_CONFIG_2, 0);
+
+ /* Disable the port */
+ if (ts->ops->ts_port_disable &&
+ (ts->tx_type != HWTSTAMP_TX_OFF ||
+ ts->rx_filter != HWTSTAMP_FILTER_NONE))
+ ts->ops->ts_port_disable(ts->dev, ts->port);
+}
+
+long marvell_ts_aux_work(struct marvell_ts *ts)
+{
+ if (!ts->irq_handler_called) {
+ if (ts->rx_filter != HWTSTAMP_FILTER_NONE) {
+ marvell_ts_rx_ts(ts, 0);
+ marvell_ts_rx_ts(ts, 1);
+ }
+
+ if (ts->tx_skb)
+ marvell_ts_txtstamp_complete(ts);
+ }
+
+ marvell_ts_rx_expire(ts);
+
+ if (ts->tx_skb)
+ return 0;
+ else if (!skb_queue_empty(&ts->rxq[0].rx_queue) ||
+ !skb_queue_empty(&ts->rxq[1].rx_queue))
+ return 1;
+
+ return -1;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_aux_work);
+
+irqreturn_t marvell_ts_irq(struct marvell_ts *ts)
+{
+ irqreturn_t ret = IRQ_NONE;
+
+ ts->irq_handler_called = true;
+
+ if (marvell_ts_rx_ts(ts, 0))
+ ret = IRQ_HANDLED;
+
+ if (marvell_ts_rx_ts(ts, 1))
+ ret = IRQ_HANDLED;
+
+ if (ts->tx_skb && marvell_ts_txtstamp_complete(ts))
+ ret = IRQ_HANDLED;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_irq);
+
+/* Configure the global (shared between ports) configuration for the PHY. */
+int marvell_ts_global_config(struct device *dev,
+ const struct marvell_ts_ops *ops)
+{
+ int err;
+
+ /* Set ether-type for IEEE1588 packets */
+ err = ops->ts_global_write(dev, PTPG_ETYPE, ETH_P_1588);
+ if (err < 0)
+ return err;
+
+ /* MsdIDTSEn - Enable timestamping on all PTP MessageIDs */
+ err = ops->ts_global_write(dev, PTPG_MSGIDTSEN, MV_PTP_MSD_ID_TS_EN);
+ if (err < 0)
+ return err;
+
+ /* TSArrPtr - Point to Arr0 registers */
+ err = ops->ts_global_write(dev, PTPG_TSARRPTR, MV_PTP_TS_ARR_PTR);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(marvell_ts_global_config);
+
+void marvell_ts_remove(struct marvell_ts *ts)
+{
+ int i;
+
+ if (!ts->tai)
+ return;
+
+ /* Ensure that the port is disabled */
+ marvell_ts_port_disable(ts);
+
+ /* Free or dequeue all pending skbs */
+ if (ts->tx_skb)
+ kfree_skb(ts->tx_skb);
+
+ for (i = 0; i < ARRAY_SIZE(ts->rxq); i++)
+ marvell_rxq_purge(&ts->rxq[i]);
+}
+EXPORT_SYMBOL_GPL(marvell_ts_remove);
+
+int marvell_ts_probe(struct marvell_ts *ts, struct device *dev,
+ struct marvell_tai *tai,
+ const struct marvell_ts_caps *caps,
+ const struct marvell_ts_ops *ops, u8 port)
+{
+ int i;
+
+ ts->ops = ops;
+ ts->dev = dev;
+ ts->tai = tai;
+ ts->caps = caps;
+ ts->port = port;
+
+ for (i = 0; i < ARRAY_SIZE(ts->rxq); i++)
+ marvell_rxq_init(&ts->rxq[i]);
+
+ /* Configure this PTP port */
+ return marvell_ts_port_config(ts);
+}
+EXPORT_SYMBOL_GPL(marvell_ts_probe);
+
+static void marvell_ts_devm_remove(void *data)
+{
+ marvell_ts_remove(data);
+}
+
+int devm_marvell_ts_probe(struct marvell_ts *ts, struct device *dev,
+ struct marvell_tai *tai,
+ const struct marvell_ts_caps *caps,
+ const struct marvell_ts_ops *ops, u8 port)
+{
+ int ret = marvell_ts_probe(ts, dev, tai, caps, ops, port);
+
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, marvell_ts_devm_remove, ts);
+}
+EXPORT_SYMBOL_GPL(devm_marvell_ts_probe);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Marvell PTP library");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/marvell_ptp.h b/include/linux/marvell_ptp.h
new file mode 100644
index 000000000000..8d70392b820c
--- /dev/null
+++ b/include/linux/marvell_ptp.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LINUX_MARVELL_PTP_H
+#define LINUX_MARVELL_PTP_H
+
+#include <linux/irqreturn.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/skbuff.h>
+#include <linux/timecounter.h>
+
+struct device;
+struct ifreq;
+struct kernel_ethtool_ts_info;
+struct marvell_tai;
+struct netlink_ext_ack;
+
+struct marvell_extts {
+ u32 time;
+ u8 status;
+#define MV_STATUS_EVENTCAPVALID BIT(8)
+};
+
+struct marvell_tai_ops {
+ int (*tai_hw_enable)(struct device *dev);
+ void (*tai_hw_disable)(struct device *dev);
+ u64 (*tai_clock_read)(struct device *dev,
+ struct ptp_system_timestamp *sts);
+ int (*tai_extts_read)(struct device *dev, int reg,
+ struct marvell_extts *extts);
+ int (*tai_pin_verify)(struct device *dev, int pin,
+ enum ptp_pin_function func, unsigned int chan);
+ int (*tai_pin_setup)(struct device *dev, int pin,
+ enum ptp_pin_function func, int enable);
+ int (*tai_write)(struct device *dev, u8 reg, u16 val);
+ int (*tai_modify)(struct device *dev, u8 reg, u16 mask, u16 val);
+ long (*tai_aux_work)(struct device *dev);
+};
+
+/* TAI module */
+struct marvell_tai_param {
+ u32 cc_mult_num;
+ u32 cc_mult_den;
+ u32 cc_mult;
+ int cc_shift;
+};
+
+struct marvell_tai_pins {
+ struct ptp_pin_desc *pins;
+ int n_pins;
+ int n_ext_ts;
+ unsigned int supported_extts_flags;
+};
+
+u64 marvell_tai_cyc2time(struct marvell_tai *tai, u32 cyc);
+int marvell_tai_ptp_clock_index(struct marvell_tai *tai);
+int marvell_tai_schedule(struct marvell_tai *tai, unsigned long delay);
+void marvell_tai_remove(struct marvell_tai *tai);
+int marvell_tai_probe(struct marvell_tai **taip,
+ const struct marvell_tai_ops *ops,
+ const struct marvell_tai_param *param,
+ const struct marvell_tai_pins *pins,
+ const char *name, struct device *dev);
+int devm_marvell_tai_probe(struct marvell_tai **taip,
+ const struct marvell_tai_ops *ops,
+ const struct marvell_tai_param *param,
+ const struct marvell_tai_pins *pins,
+ const char *name, struct device *dev);
+
+/* Timestamping module */
+struct marvell_hwts {
+ u32 time;
+ u16 stat;
+#define MV_STATUS_INTSTATUS_MASK 0x0006
+#define MV_STATUS_INTSTATUS_NORMAL 0x0000
+#define MV_STATUS_VALID BIT(0)
+ u16 seq;
+};
+
+enum marvell_ts_reg {
+ MARVELL_TS_ARR0,
+ MARVELL_TS_ARR1,
+ MARVELL_TS_DEP,
+};
+
+struct marvell_ts_ops {
+ int (*ts_global_write)(struct device *dev, u8 reg, u16 val);
+ int (*ts_port_enable)(struct device *dev, u8 port);
+ void (*ts_port_disable)(struct device *dev, u8 port);
+ int (*ts_port_read_ts)(struct device *dev, struct marvell_hwts *ts,
+ u8 port, enum marvell_ts_reg ts_reg);
+ int (*ts_port_write)(struct device *dev, u8 port, u8 reg, u16 val);
+ int (*ts_port_modify)(struct device *dev, u8 port, u8 reg, u16 mask,
+ u16 val);
+};
+
+struct marvell_ts_caps {
+ u32 rx_filters;
+};
+
+struct marvell_rxts {
+ struct list_head node;
+ u64 ns;
+ u16 seq;
+};
+
+struct marvell_rxq {
+ struct mutex rx_mutex;
+ struct list_head rx_free;
+ struct list_head rx_pend;
+ struct sk_buff_head rx_queue;
+ struct marvell_rxts rx_ts[64];
+};
+
+struct marvell_ts {
+ struct marvell_tai *tai;
+ const struct marvell_ts_ops *ops;
+ struct device *dev;
+
+ /* We only support one outstanding transmit skb */
+ struct sk_buff *tx_skb;
+ enum hwtstamp_tx_types tx_type;
+
+ struct marvell_rxq rxq[2];
+ enum hwtstamp_rx_filters rx_filter;
+
+ const struct marvell_ts_caps *caps;
+ u8 port;
+
+ bool irq_handler_called;
+};
+
+bool marvell_ts_rxtstamp(struct marvell_ts *ts, struct sk_buff *skb, int type);
+bool marvell_ts_txtstamp(struct marvell_ts *ts, struct sk_buff *skb, int type);
+int marvell_ts_hwtstamp_get(struct marvell_ts *ts,
+ struct kernel_hwtstamp_config *kcfg);
+int marvell_ts_hwtstamp_set(struct marvell_ts *ts,
+ struct kernel_hwtstamp_config *kcfg,
+ struct netlink_ext_ack *ack);
+int marvell_ts_info(struct marvell_ts *ts,
+ struct kernel_ethtool_ts_info *ts_info);
+long marvell_ts_aux_work(struct marvell_ts *ts);
+irqreturn_t marvell_ts_irq(struct marvell_ts *ts);
+int marvell_ts_global_config(struct device *dev,
+ const struct marvell_ts_ops *ops);
+
+void marvell_ts_remove(struct marvell_ts *ts);
+int marvell_ts_probe(struct marvell_ts *ts, struct device *dev,
+ struct marvell_tai *tai,
+ const struct marvell_ts_caps *caps,
+ const struct marvell_ts_ops *ops, u8 port);
+int devm_marvell_ts_probe(struct marvell_ts *ts, struct device *dev,
+ struct marvell_tai *tai,
+ const struct marvell_ts_caps *caps,
+ const struct marvell_ts_ops *ops, u8 port);
+
+#endif
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 02/20] net: phy: add hwtstamp_get() method for mii timestampers
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
2025-09-18 17:38 ` [PATCH RFC net-next 01/20] ptp: marvell: add core support for Marvell PTP Russell King
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:38 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support Russell King
` (17 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Add the missing hwtstamp_get() method for mii timestampers so PHYs can
report their configuration back to userspace.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phy.c | 3 +++
include/linux/mii_timestamper.h | 3 +++
2 files changed, 6 insertions(+)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e046dd858f15..b028c53c459a 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -476,6 +476,9 @@ int __phy_hwtstamp_get(struct phy_device *phydev,
if (!phydev)
return -ENODEV;
+ if (phydev->mii_ts && phydev->mii_ts->hwtstamp_get)
+ return phydev->mii_ts->hwtstamp_get(phydev->mii_ts, config);
+
return -EOPNOTSUPP;
}
diff --git a/include/linux/mii_timestamper.h b/include/linux/mii_timestamper.h
index 995db62570f9..a71f03d1585f 100644
--- a/include/linux/mii_timestamper.h
+++ b/include/linux/mii_timestamper.h
@@ -55,6 +55,9 @@ struct mii_timestamper {
struct kernel_hwtstamp_config *kernel_config,
struct netlink_ext_ack *extack);
+ int (*hwtstamp_get)(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *kernel_config);
+
void (*link_state)(struct mii_timestamper *mii_ts,
struct phy_device *phydev);
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
2025-09-18 17:38 ` [PATCH RFC net-next 01/20] ptp: marvell: add core support for Marvell PTP Russell King
2025-09-18 17:39 ` [PATCH RFC net-next 02/20] net: phy: add hwtstamp_get() method for mii timestampers Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King
2025-09-18 20:12 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 04/20] net: dsa: mv88e6xxx: split out set_ptp_cpu_port() code Russell King (Oracle)
` (16 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Add PTP basic support for Marvell 88E151x PHYs. These PHYs support
timestamping the egress and ingress of packets, but does not support
any packet modification, nor do we support any filtering beyond
selecting packets that the hardware recognises as PTP/802.1AS.
The PHYs support hardware pins for providing an external clock for the
TAI counter, and a separate pin that can be used for event capture or
generation of a trigger (either a pulse or periodic). This code does
not support either of these modes.
We currently use a delayed work to poll for the timestamps which is
far from ideal, but we also provide a function that can be called from
an interrupt handler - which would be good to tie into the main Marvell
PHY driver.
The driver takes inspiration from the Marvell 88E6xxx DSA and DP83640
drivers. The hardware is very similar to the implementation found in
the 88E6xxx DSA driver, but the access methods are very different,
although it may be possible to create a library that both can use
along with accessor functions.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/Kconfig | 13 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/marvell.c | 15 +-
drivers/net/phy/marvell_ptp.c | 369 ++++++++++++++++++++++++++++++++++
drivers/net/phy/marvell_ptp.h | 17 ++
5 files changed, 414 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/phy/marvell_ptp.c
create mode 100644 drivers/net/phy/marvell_ptp.h
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index ca05166ae605..ac29dc94a575 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -253,6 +253,19 @@ config MARVELL_PHY
help
Currently has a driver for the 88E1XXX
+config MARVELL_PHY_PTP
+ bool "Marvell PHY PTP support"
+ depends on NETWORK_PHY_TIMESTAMPING
+ depends on (MARVELL_PHY = y && PTP_1588_CLOCK = y) || \
+ (MARVELL_PHY = m && PTP_1588_CLOCK)
+ select PTP_1588_CLOCK_MARVELL
+ help
+ Support PHY timestamping on Marvell 88E1510, 88E1512, 88E1514
+ and 88E1518 PHYs.
+
+ N.B. In order for this to be fully functional, your MAC driver
+ must call the skb_tx_timestamp() function.
+
config MARVELL_10G_PHY
tristate "Marvell Alaska 10Gbit PHYs"
help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 76e0db40f879..113eee38f253 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_LXT_PHY) += lxt.o
+obj-$(CONFIG_MARVELL_PHY_PTP) += marvell_ptp.o
obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 0ea366c1217e..745f95a71fc0 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -38,6 +38,8 @@
#include <asm/irq.h>
#include <linux/uaccess.h>
+#include "marvell_ptp.h"
+
#define MII_MARVELL_PHY_PAGE 22
#define MII_MARVELL_COPPER_PAGE 0x00
#define MII_MARVELL_FIBER_PAGE 0x01
@@ -3684,7 +3686,7 @@ static const struct sfp_upstream_ops m88e1510_sfp_ops = {
.disconnect_phy = phy_sfp_disconnect_phy,
};
-static int m88e1510_probe(struct phy_device *phydev)
+static int m88e15xx_probe(struct phy_device *phydev)
{
int err;
@@ -3695,6 +3697,17 @@ static int m88e1510_probe(struct phy_device *phydev)
return phy_sfp_probe(phydev, &m88e1510_sfp_ops);
}
+static int m88e1510_probe(struct phy_device *phydev)
+{
+ int err;
+
+ err = m88e15xx_probe(phydev);
+ if (err)
+ return err;
+
+ return devm_marvell_phy_ptp_probe(phydev);
+}
+
static struct phy_driver marvell_drivers[] = {
{
.phy_id = MARVELL_PHY_ID_88E1101,
diff --git a/drivers/net/phy/marvell_ptp.c b/drivers/net/phy/marvell_ptp.c
new file mode 100644
index 000000000000..662881df7fdf
--- /dev/null
+++ b/drivers/net/phy/marvell_ptp.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Marvell PTP driver for 88E1510, 88E1512, 88E1514 and 88E1518 PHYs
+ *
+ * Ideas taken from 88E6xxx DSA and DP83640 drivers. This file
+ * implements the packet timestamping support only (PTP). TAI
+ * support is separate.
+ */
+#include <linux/marvell_ptp.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "marvell_ptp.h"
+
+#define MARVELL_PAGE_MISC 6
+#define GCR 20
+#define GCR_PTP_POWER_DOWN BIT(9)
+#define GCR_PTP_REF_CLOCK_SOURCE BIT(8)
+#define GCR_PTP_INPUT_SOURCE BIT(7)
+#define GCR_PTP_OUTPUT BIT(6)
+
+#define MARVELL_PAGE_PTP_PORT_1 8
+#define PTPP1_ARR0_STATUS 8
+#define PTPP1_ARR1_STATUS 12
+#define MARVELL_PAGE_PTP_PORT_2 9
+#define PTPP2_DEP_STATUS 0
+
+#define MARVELL_PAGE_TAI_GLOBAL 12
+#define MARVELL_PAGE_PTP_GLOBAL 14
+#define PTPG_READPLUS_COMMAND 14
+#define PTPG_READPLUS_DATA 15
+
+/* 88E151x has PTP Global Configuration 3
+ * 0 TSAtSFD - Timestamp at start of frame delimiter
+ */
+#define PTPG_CONFIG_3 3
+#define PTPG_CONFIG_3_TSATSFD BIT(0)
+
+struct marvell_phy_ptp {
+ struct mii_timestamper mii_ts;
+ struct marvell_ts ts;
+};
+
+static struct marvell_phy_ptp *mii_ts_to_phy_ptp(struct mii_timestamper *mii_ts)
+{
+ return container_of(mii_ts, struct marvell_phy_ptp, mii_ts);
+}
+
+static bool marvell_phy_ptp_rxtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct marvell_phy_ptp *phy_ptp = mii_ts_to_phy_ptp(mii_ts);
+
+ return marvell_ts_rxtstamp(&phy_ptp->ts, skb, type);
+}
+
+static void marvell_phy_ptp_txtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct marvell_phy_ptp *phy_ptp = mii_ts_to_phy_ptp(mii_ts);
+
+ if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ||
+ !marvell_ts_txtstamp(&phy_ptp->ts, skb, type))
+ kfree_skb(skb);
+}
+
+static int marvell_phy_ptp_hwtstamp(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *kcfg,
+ struct netlink_ext_ack *ack)
+{
+ struct marvell_phy_ptp *phy_ptp = mii_ts_to_phy_ptp(mii_ts);
+
+ return marvell_ts_hwtstamp_set(&phy_ptp->ts, kcfg, ack);
+}
+
+static int marvell_phy_ptp_hwtstamp_get(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *kcfg)
+{
+ struct marvell_phy_ptp *phy_ptp = mii_ts_to_phy_ptp(mii_ts);
+
+ return marvell_ts_hwtstamp_get(&phy_ptp->ts, kcfg);
+}
+
+static int marvell_phy_ptp_ts_info(struct mii_timestamper *mii_ts,
+ struct kernel_ethtool_ts_info *ts_info)
+{
+ struct marvell_phy_ptp *phy_ptp = mii_ts_to_phy_ptp(mii_ts);
+
+ return marvell_ts_info(&phy_ptp->ts, ts_info);
+}
+
+/* TAI accessor functions */
+static int marvell_phy_tai_hw_enable(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return phy_modify_paged(phydev, MARVELL_PAGE_MISC, GCR,
+ GCR_PTP_POWER_DOWN, 0);
+}
+
+static void marvell_phy_tai_hw_disable(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ phy_modify_paged(phydev, MARVELL_PAGE_MISC, GCR,
+ GCR_PTP_POWER_DOWN, GCR_PTP_POWER_DOWN);
+}
+
+static u64 marvell_phy_tai_clock_read(struct device *dev,
+ struct ptp_system_timestamp *sts)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ int err, oldpage, lo, hi;
+
+ oldpage = phy_select_page(phydev, MARVELL_PAGE_PTP_GLOBAL);
+ if (oldpage >= 0) {
+ /* 88e151x says to write 0x8e0e */
+ ptp_read_system_prets(sts);
+ err = __phy_write(phydev, PTPG_READPLUS_COMMAND, 0x8e0e);
+ ptp_read_system_postts(sts);
+ lo = __phy_read(phydev, PTPG_READPLUS_DATA);
+ hi = __phy_read(phydev, PTPG_READPLUS_DATA);
+ }
+ err = phy_restore_page(phydev, oldpage, err);
+
+ if (err || lo < 0 || hi < 0)
+ return 0;
+
+ return lo | hi << 16;
+}
+
+static int marvell_phy_tai_write(struct device *dev, u8 reg, u16 val)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return phy_write_paged(phydev, MARVELL_PAGE_TAI_GLOBAL, reg, val);
+}
+
+static int marvell_phy_tai_modify(struct device *dev, u8 reg, u16 mask, u16 val)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return phy_modify_paged(phydev, MARVELL_PAGE_TAI_GLOBAL,
+ reg, mask, val);
+}
+
+static long marvell_phy_tai_aux_work(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct marvell_phy_ptp *phy_ptp;
+
+ phy_ptp = mii_ts_to_phy_ptp(phydev->mii_ts);
+
+ return marvell_ts_aux_work(&phy_ptp->ts);
+}
+
+static const struct marvell_tai_ops marvell_phy_tai_ops = {
+ .tai_hw_enable = marvell_phy_tai_hw_enable,
+ .tai_hw_disable = marvell_phy_tai_hw_disable,
+ .tai_clock_read = marvell_phy_tai_clock_read,
+ .tai_write = marvell_phy_tai_write,
+ .tai_modify = marvell_phy_tai_modify,
+ .tai_aux_work = marvell_phy_tai_aux_work,
+};
+
+static const struct marvell_tai_param marvell_phy_tai_param = {
+ /* This assumes a 125MHz clock */
+ .cc_mult_num = 1 << 9,
+ .cc_mult_den = 15625U,
+ .cc_mult = 8 << 28,
+ .cc_shift = 28,
+};
+
+static int marvell_phy_ts_global_write(struct device *dev, u8 reg, u16 val)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return phy_write_paged(phydev, MARVELL_PAGE_PTP_GLOBAL, reg, val);
+}
+
+static const struct {
+ u8 page;
+ u8 reg;
+} marvell_phy_ts_ts_reg[] = {
+ [MARVELL_TS_ARR0] = {
+ .page = MARVELL_PAGE_PTP_PORT_1,
+ .reg = PTPP1_ARR0_STATUS,
+ },
+ [MARVELL_TS_ARR1] = {
+ .page = MARVELL_PAGE_PTP_PORT_1,
+ .reg = PTPP1_ARR1_STATUS,
+ },
+ [MARVELL_TS_DEP] = {
+ .page = MARVELL_PAGE_PTP_PORT_2,
+ .reg = PTPP2_DEP_STATUS,
+ },
+};
+
+/* Read the status, timestamp and PTP common header sequence from the PHY.
+ * Apparently, reading these are atomic, but there is no mention how the
+ * PHY treats this access as atomic. So, we set the DisTSOverwrite bit
+ * when configuring the PHY.
+ */
+static int marvell_phy_ts_port_read_ts(struct device *dev,
+ struct marvell_hwts *hwts, u8 port,
+ enum marvell_ts_reg ts_reg)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ int oldpage, page, reg;
+ int ret;
+
+ page = marvell_phy_ts_ts_reg[ts_reg].page;
+ reg = marvell_phy_ts_ts_reg[ts_reg].reg;
+
+ /* Read status register */
+ oldpage = phy_select_page(phydev, page);
+ if (oldpage >= 0) {
+ ret = __phy_read(phydev, reg);
+ if (ret < 0)
+ goto restore;
+
+ hwts->stat = ret;
+ if (!(hwts->stat & MV_STATUS_VALID)) {
+ ret = 0;
+ goto restore;
+ }
+
+ /* Read low timestamp */
+ ret = __phy_read(phydev, reg + 1);
+ if (ret < 0)
+ goto restore;
+
+ hwts->time = ret;
+
+ /* Read high timestamp */
+ ret = __phy_read(phydev, reg + 2);
+ if (ret < 0)
+ goto restore;
+
+ hwts->time |= ret << 16;
+
+ /* Read sequence */
+ ret = __phy_read(phydev, reg + 3);
+ if (ret < 0)
+ goto restore;
+
+ hwts->seq = ret;
+
+ /* Clear valid */
+ __phy_write(phydev, reg, 0);
+
+ ret = 1;
+ }
+restore:
+ return phy_restore_page(phydev, oldpage, ret);
+}
+
+static int marvell_phy_ts_port_write(struct device *dev, u8 port, u8 reg,
+ u16 val)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return phy_write_paged(phydev, MARVELL_PAGE_PTP_PORT_1 + (reg >> 4),
+ reg & 15, val);
+}
+
+static int marvell_phy_ts_port_modify(struct device *dev, u8 port, u8 reg,
+ u16 mask, u16 val)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return phy_modify_paged(phydev, MARVELL_PAGE_PTP_PORT_1 + (reg >> 4),
+ reg & 15, mask, val);
+}
+
+static const struct marvell_ts_ops marvell_phy_ts_ops = {
+ .ts_global_write = marvell_phy_ts_global_write,
+ .ts_port_read_ts = marvell_phy_ts_port_read_ts,
+ .ts_port_write = marvell_phy_ts_port_write,
+ .ts_port_modify = marvell_phy_ts_port_modify,
+};
+
+/* This function should be called from the PHY threaded interrupt
+ * handler to process any stored timestamps in a timely manner.
+ * The presence of an interrupt has an effect on how quickly a
+ * timestamp requiring received packet will be processed.
+ */
+irqreturn_t marvell_phy_ptp_irq(struct phy_device *phydev)
+{
+ struct marvell_phy_ptp *phy_ptp;
+
+ if (!phydev->mii_ts)
+ return IRQ_NONE;
+
+ phy_ptp = mii_ts_to_phy_ptp(phydev->mii_ts);
+
+ return marvell_ts_irq(&phy_ptp->ts);
+}
+EXPORT_SYMBOL_GPL(marvell_phy_ptp_irq);
+
+static void marvell_phy_ptp_remove(void *_data)
+{
+ struct phy_device *phydev = _data;
+
+ /* Disconnect from the net subsystem - we assume there is no
+ * packet activity at this point.
+ */
+ phydev->mii_ts = NULL;
+}
+
+/* 88e1510 can filter on 802.1AS frames, IEEE1588v1/v2 frames or both.
+ * 802.1AS frames can be matched by TransSpec = 1
+ */
+static const struct marvell_ts_caps marvell_phy_ts_caps = {
+ .rx_filters = BIT(HWTSTAMP_FILTER_SOME),
+};
+
+int devm_marvell_phy_ptp_probe(struct phy_device *phydev)
+{
+ struct marvell_phy_ptp *phy_ptp;
+ struct marvell_tai *tai;
+ struct device *dev;
+ int err;
+
+ dev = &phydev->mdio.dev;
+
+ phy_ptp = devm_kzalloc(dev, sizeof(*phy_ptp), GFP_KERNEL);
+ if (!phy_ptp)
+ return -ENOMEM;
+
+ phy_ptp->mii_ts.rxtstamp = marvell_phy_ptp_rxtstamp;
+ phy_ptp->mii_ts.txtstamp = marvell_phy_ptp_txtstamp;
+ phy_ptp->mii_ts.hwtstamp = marvell_phy_ptp_hwtstamp;
+ phy_ptp->mii_ts.hwtstamp_get = marvell_phy_ptp_hwtstamp_get;
+ phy_ptp->mii_ts.ts_info = marvell_phy_ptp_ts_info;
+
+ /* Get the TAI for this PHY. */
+ err = devm_marvell_tai_probe(&tai, &marvell_phy_tai_ops,
+ &marvell_phy_tai_param, NULL,
+ "Marvell PHY", dev);
+ if (err)
+ return err;
+
+ /* Setup the global PTP configuration */
+ err = marvell_ts_global_config(dev, &marvell_phy_ts_ops);
+ if (err)
+ return err;
+
+ /* PHY specific global configuration - set TSAtSFD, timestamp at SFD */
+ err = marvell_phy_ts_global_write(dev, PTPG_CONFIG_3,
+ PTPG_CONFIG_3_TSATSFD);
+ if (err < 0)
+ return err;
+
+ err = devm_marvell_ts_probe(&phy_ptp->ts, dev, tai,
+ &marvell_phy_ts_caps,
+ &marvell_phy_ts_ops, 0);
+ if (err)
+ return err;
+
+ phydev->mii_ts = &phy_ptp->mii_ts;
+
+ return devm_add_action_or_reset(dev, marvell_phy_ptp_remove, phydev);
+}
+EXPORT_SYMBOL_GPL(devm_marvell_phy_ptp_probe);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Marvell PHY PTP library");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/phy/marvell_ptp.h b/drivers/net/phy/marvell_ptp.h
new file mode 100644
index 000000000000..7e712aed2eaa
--- /dev/null
+++ b/drivers/net/phy/marvell_ptp.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef MARVELL_PTP_H
+#define MARVELL_PTP_H
+
+#if IS_ENABLED(CONFIG_MARVELL_PHY_PTP)
+irqreturn_t marvell_phy_ptp_irq(struct phy_device *phydev);
+int devm_marvell_phy_ptp_probe(struct phy_device *phydev);
+#else
+static inline int marvell_phy_ptp_dummy_probe(void)
+{
+ return 0;
+}
+#define devm_marvell_phy_ptp_probe(x...) marvell_phy_ptp_dummy_probe()
+
+#endif
+
+#endif
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 04/20] net: dsa: mv88e6xxx: split out set_ptp_cpu_port() code
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (2 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support Russell King
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:46 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 05/20] net: dsa: mv88e6xxx: convert PTP clock_read() method to take chip Russell King (Oracle)
` (15 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Split out the code which sets up the upstream CPU port for PTP. This
will be required when converted to the generic Marvell PTP library.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/ptp.c | 42 ++++++++++++++++++++-------------
1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index f7603573d3a9..b60e4f02c256 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -444,6 +444,27 @@ const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = {
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
};
+static int mv88e6xxx_set_ptp_cpu_port(struct mv88e6xxx_chip *chip)
+{
+ struct dsa_port *dp;
+ int upstream = 0;
+ int err;
+
+ if (!chip->info->ops->ptp_ops->set_ptp_cpu_port)
+ return 0;
+
+ dsa_switch_for_each_user_port(dp, chip->ds) {
+ upstream = dsa_upstream_port(chip->ds, dp->index);
+ break;
+ }
+
+ err = chip->info->ops->ptp_ops->set_ptp_cpu_port(chip, upstream);
+ if (err)
+ dev_err(chip->dev, "Failed to set PTP CPU destination port!\n");
+
+ return err;
+}
+
static u64 mv88e6xxx_ptp_clock_read(struct cyclecounter *cc)
{
struct mv88e6xxx_chip *chip = cc_to_chip(cc);
@@ -473,7 +494,7 @@ static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
- int i;
+ int err, i;
/* Set up the cycle counter */
chip->cc_coeffs = mv88e6xxx_cc_coeff_get(chip);
@@ -524,22 +545,9 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
PTP_FALLING_EDGE |
PTP_STRICT_FLAGS;
- if (ptp_ops->set_ptp_cpu_port) {
- struct dsa_port *dp;
- int upstream = 0;
- int err;
-
- dsa_switch_for_each_user_port(dp, chip->ds) {
- upstream = dsa_upstream_port(chip->ds, dp->index);
- break;
- }
-
- err = ptp_ops->set_ptp_cpu_port(chip, upstream);
- if (err) {
- dev_err(chip->dev, "Failed to set PTP CPU destination port!\n");
- return err;
- }
- }
+ err = mv88e6xxx_set_ptp_cpu_port(chip);
+ if (err)
+ return err;
chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev);
if (IS_ERR(chip->ptp_clock))
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 05/20] net: dsa: mv88e6xxx: convert PTP clock_read() method to take chip
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (3 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 04/20] net: dsa: mv88e6xxx: split out set_ptp_cpu_port() code Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:13 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 06/20] net: dsa: mv88e6xxx: convert PTP ptp_verify() " Russell King (Oracle)
` (14 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
The various clock_read() method implementations do not make use of the
passed struct cycle_counter except to convert to the parent struct
mv88e6xxx_chip. The caller of these methods has already done this.
Pass a pointer to struct mv88e6xxx_chip instead.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.h | 2 +-
drivers/net/dsa/mv88e6xxx/ptp.c | 8 +++-----
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 2f211e55cb47..fd91d2252735 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -730,7 +730,7 @@ struct mv88e6xxx_avb_ops {
};
struct mv88e6xxx_ptp_ops {
- u64 (*clock_read)(struct cyclecounter *cc);
+ u64 (*clock_read)(struct mv88e6xxx_chip *chip);
int (*ptp_enable)(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on);
int (*ptp_verify)(struct ptp_clock_info *ptp, unsigned int pin,
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index b60e4f02c256..d907ba04eddd 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -138,9 +138,8 @@ mv88e6xxx_cc_coeff_get(struct mv88e6xxx_chip *chip)
}
}
-static u64 mv88e6352_ptp_clock_read(struct cyclecounter *cc)
+static u64 mv88e6352_ptp_clock_read(struct mv88e6xxx_chip *chip)
{
- struct mv88e6xxx_chip *chip = cc_to_chip(cc);
u16 phc_time[2];
int err;
@@ -152,9 +151,8 @@ static u64 mv88e6352_ptp_clock_read(struct cyclecounter *cc)
return ((u32)phc_time[1] << 16) | phc_time[0];
}
-static u64 mv88e6165_ptp_clock_read(struct cyclecounter *cc)
+static u64 mv88e6165_ptp_clock_read(struct mv88e6xxx_chip *chip)
{
- struct mv88e6xxx_chip *chip = cc_to_chip(cc);
u16 phc_time[2];
int err;
@@ -470,7 +468,7 @@ static u64 mv88e6xxx_ptp_clock_read(struct cyclecounter *cc)
struct mv88e6xxx_chip *chip = cc_to_chip(cc);
if (chip->info->ops->ptp_ops->clock_read)
- return chip->info->ops->ptp_ops->clock_read(cc);
+ return chip->info->ops->ptp_ops->clock_read(chip);
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 06/20] net: dsa: mv88e6xxx: convert PTP ptp_verify() method to take chip
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (4 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 05/20] net: dsa: mv88e6xxx: convert PTP clock_read() method to take chip Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:48 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 07/20] net: dsa: mv88e6xxx: convert PTP ptp_enable() " Russell King (Oracle)
` (13 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Wrap the ptp_ops->ptp_verify() method and convert it to take
struct mv88e6xxx_chip. This eases the transition to generic Marvell
PTP.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.h | 2 +-
drivers/net/dsa/mv88e6xxx/ptp.c | 12 ++++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index fd91d2252735..ca62994f650a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -733,7 +733,7 @@ struct mv88e6xxx_ptp_ops {
u64 (*clock_read)(struct mv88e6xxx_chip *chip);
int (*ptp_enable)(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on);
- int (*ptp_verify)(struct ptp_clock_info *ptp, unsigned int pin,
+ int (*ptp_verify)(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan);
void (*event_work)(struct work_struct *ugly);
int (*port_enable)(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index d907ba04eddd..87d7fe407862 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -306,6 +306,14 @@ static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
return 0;
}
+static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+
+ return chip->info->ops->ptp_ops->ptp_verify(chip, pin, func, chan);
+}
+
static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
struct ptp_clock_request *rq, int on)
{
@@ -365,7 +373,7 @@ static int mv88e6352_ptp_enable(struct ptp_clock_info *ptp,
}
}
-static int mv88e6352_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
+static int mv88e6352_ptp_verify(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan)
{
switch (func) {
@@ -536,7 +544,7 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime;
chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime;
chip->ptp_clock_info.enable = ptp_ops->ptp_enable;
- chip->ptp_clock_info.verify = ptp_ops->ptp_verify;
+ chip->ptp_clock_info.verify = mv88e6xxx_ptp_verify;
chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work;
chip->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE |
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 07/20] net: dsa: mv88e6xxx: convert PTP ptp_enable() method to take chip
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (5 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 06/20] net: dsa: mv88e6xxx: convert PTP ptp_verify() " Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:48 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 08/20] net: dsa: mv88e6xxx: convert mv88e6xxx_hwtstamp_work() " Russell King (Oracle)
` (12 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Wrap the ptp_ops->ptp_enable() method and convert it to take
struct mv88e6xxx_chip. This eases the transition to generic Marvell
PTP.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.h | 2 +-
drivers/net/dsa/mv88e6xxx/ptp.c | 14 ++++++++++----
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index ca62994f650a..7618f6db235e 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -731,7 +731,7 @@ struct mv88e6xxx_avb_ops {
struct mv88e6xxx_ptp_ops {
u64 (*clock_read)(struct mv88e6xxx_chip *chip);
- int (*ptp_enable)(struct ptp_clock_info *ptp,
+ int (*ptp_enable)(struct mv88e6xxx_chip *chip,
struct ptp_clock_request *rq, int on);
int (*ptp_verify)(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 87d7fe407862..43c4af82cb1c 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -306,6 +306,14 @@ static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
return 0;
}
+static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *req, int enable)
+{
+ struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+
+ return chip->info->ops->ptp_ops->ptp_enable(chip, req, enable);
+}
+
static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
enum ptp_pin_function func, unsigned int chan)
{
@@ -360,11 +368,9 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
return err;
}
-static int mv88e6352_ptp_enable(struct ptp_clock_info *ptp,
+static int mv88e6352_ptp_enable(struct mv88e6xxx_chip *chip,
struct ptp_clock_request *rq, int on)
{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
-
switch (rq->type) {
case PTP_CLK_REQ_EXTTS:
return mv88e6352_ptp_enable_extts(chip, rq, on);
@@ -543,7 +549,7 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
chip->ptp_clock_info.adjtime = mv88e6xxx_ptp_adjtime;
chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime;
chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime;
- chip->ptp_clock_info.enable = ptp_ops->ptp_enable;
+ chip->ptp_clock_info.enable = mv88e6xxx_ptp_enable;
chip->ptp_clock_info.verify = mv88e6xxx_ptp_verify;
chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work;
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 08/20] net: dsa: mv88e6xxx: convert mv88e6xxx_hwtstamp_work() to take chip
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (6 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 07/20] net: dsa: mv88e6xxx: convert PTP ptp_enable() " Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:51 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 09/20] net: dsa: mv88e6xxx: always verify PTP_PF_NONE Russell King (Oracle)
` (11 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Instead of passing a pointer to the ptp_clock_info structure, pass a
pointer to mv88e6xxx_chip instead. This allows the transition to the
generic marvell PTP library easier.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 3 +--
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 2 +-
drivers/net/dsa/mv88e6xxx/ptp.c | 7 ++++++-
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 6e6472a3b75a..ba989d699113 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -439,9 +439,8 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
return 0;
}
-long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
+long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip)
{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
struct dsa_switch *ds = chip->ds;
struct mv88e6xxx_port_hwtstamp *ps;
int i, restart = 0;
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index c359821d5a6e..747351d59921 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -124,7 +124,7 @@ void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct kernel_ethtool_ts_info *info);
-long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp);
+long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip);
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip);
int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 43c4af82cb1c..03f30424ba97 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -503,6 +503,11 @@ static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
MV88E6XXX_TAI_OVERFLOW_PERIOD);
}
+static long mv88e6xxx_ptp_aux_work(struct ptp_clock_info *ptp)
+{
+ return mv88e6xxx_hwtstamp_work(ptp_to_chip(ptp));
+}
+
int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
@@ -551,7 +556,7 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime;
chip->ptp_clock_info.enable = mv88e6xxx_ptp_enable;
chip->ptp_clock_info.verify = mv88e6xxx_ptp_verify;
- chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work;
+ chip->ptp_clock_info.do_aux_work = mv88e6xxx_ptp_aux_work;
chip->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE |
PTP_FALLING_EDGE |
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 09/20] net: dsa: mv88e6xxx: always verify PTP_PF_NONE
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (7 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 08/20] net: dsa: mv88e6xxx: convert mv88e6xxx_hwtstamp_work() " Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:14 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 10/20] net: dsa: mv88e6xxx: only support EXTTS for pins Russell King (Oracle)
` (10 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Setting a pin to "no function" should always be supported. Move this
to mv88e6xxx_ptp_verify(). This allows mv88e6352_ptp_verify() to be
simplified as the only supported PTP pin mode function is
PTP_PF_EXTTS.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/ptp.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 03f30424ba97..72ad6be05943 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -319,6 +319,10 @@ static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
{
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+ /* Always allow a pin to be set to no function */
+ if (func == PTP_PF_NONE)
+ return 0;
+
return chip->info->ops->ptp_ops->ptp_verify(chip, pin, func, chan);
}
@@ -382,14 +386,9 @@ static int mv88e6352_ptp_enable(struct mv88e6xxx_chip *chip,
static int mv88e6352_ptp_verify(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan)
{
- switch (func) {
- case PTP_PF_NONE:
- case PTP_PF_EXTTS:
- break;
- case PTP_PF_PEROUT:
- case PTP_PF_PHYSYNC:
+ if (func != PTP_PF_EXTTS)
return -EOPNOTSUPP;
- }
+
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 10/20] net: dsa: mv88e6xxx: only support EXTTS for pins
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (8 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 09/20] net: dsa: mv88e6xxx: always verify PTP_PF_NONE Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-19 11:29 ` Vadim Fedorenko
2025-09-18 17:39 ` [PATCH RFC net-next 11/20] net: dsa: mv88e6xxx: split out EXTTS pin setup Russell King (Oracle)
` (9 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
The sole implementation for the PTP verify/enable methods only supports
the EXTTS function. Move these checks into mv88e6xxx_ptp_verify() and
mv88e6xxx_ptp_enable(), renaming the ptp_enable() method to
ptp_enable_extts().
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.h | 4 ++--
drivers/net/dsa/mv88e6xxx/ptp.c | 26 +++++++++-----------------
2 files changed, 11 insertions(+), 19 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 7618f6db235e..ae56a88ca1c5 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -731,8 +731,8 @@ struct mv88e6xxx_avb_ops {
struct mv88e6xxx_ptp_ops {
u64 (*clock_read)(struct mv88e6xxx_chip *chip);
- int (*ptp_enable)(struct mv88e6xxx_chip *chip,
- struct ptp_clock_request *rq, int on);
+ int (*ptp_enable_extts)(struct mv88e6xxx_chip *chip,
+ struct ptp_clock_request *rq, int on);
int (*ptp_verify)(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan);
void (*event_work)(struct work_struct *ugly);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 72ad6be05943..de44622d8513 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -311,7 +311,10 @@ static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
{
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
- return chip->info->ops->ptp_ops->ptp_enable(chip, req, enable);
+ if (req->type != PTP_CLK_REQ_EXTTS)
+ return -EOPNOTSUPP;
+
+ return chip->info->ops->ptp_ops->ptp_enable_extts(chip, req, enable);
}
static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
@@ -323,6 +326,9 @@ static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
if (func == PTP_PF_NONE)
return 0;
+ if (func != PTP_PF_EXTTS)
+ return -EOPNOTSUPP;
+
return chip->info->ops->ptp_ops->ptp_verify(chip, pin, func, chan);
}
@@ -372,23 +378,9 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
return err;
}
-static int mv88e6352_ptp_enable(struct mv88e6xxx_chip *chip,
- struct ptp_clock_request *rq, int on)
-{
- switch (rq->type) {
- case PTP_CLK_REQ_EXTTS:
- return mv88e6352_ptp_enable_extts(chip, rq, on);
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int mv88e6352_ptp_verify(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan)
{
- if (func != PTP_PF_EXTTS)
- return -EOPNOTSUPP;
-
return 0;
}
@@ -410,7 +402,7 @@ const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
.clock_read = mv88e6352_ptp_clock_read,
- .ptp_enable = mv88e6352_ptp_enable,
+ .ptp_enable_extts = mv88e6352_ptp_enable_extts,
.ptp_verify = mv88e6352_ptp_verify,
.event_work = mv88e6352_tai_event_work,
.port_enable = mv88e6352_hwtstamp_port_enable,
@@ -433,7 +425,7 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = {
.clock_read = mv88e6352_ptp_clock_read,
- .ptp_enable = mv88e6352_ptp_enable,
+ .ptp_enable_extts = mv88e6352_ptp_enable_extts,
.ptp_verify = mv88e6352_ptp_verify,
.event_work = mv88e6352_tai_event_work,
.port_enable = mv88e6352_hwtstamp_port_enable,
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 11/20] net: dsa: mv88e6xxx: split out EXTTS pin setup
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (9 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 10/20] net: dsa: mv88e6xxx: only support EXTTS for pins Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 20:59 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 12/20] net: dsa: mv88e6xxx: move EXTTS flag validation and pin lookup Russell King (Oracle)
` (8 subsequent siblings)
19 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Split out the EXTTS pin setup from the extts configuration.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/ptp.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index de44622d8513..19ccc8cda1f0 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -111,6 +111,20 @@ static int mv88e6352_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
return chip->info->ops->gpio_ops->set_pctl(chip, pin, func);
}
+static int mv88e6352_ptp_pin_setup(struct mv88e6xxx_chip *chip, int pin,
+ enum ptp_pin_function func, int enable)
+{
+ if (func != PTP_PF_EXTTS)
+ return -EOPNOTSUPP;
+
+ if (enable)
+ func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
+ else
+ func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO;
+
+ return mv88e6352_set_gpio_func(chip, pin, func, true);
+}
+
static const struct mv88e6xxx_cc_coeffs *
mv88e6xxx_cc_coeff_get(struct mv88e6xxx_chip *chip)
{
@@ -352,27 +366,18 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
return -EBUSY;
mv88e6xxx_reg_lock(chip);
+ err = mv88e6352_ptp_pin_setup(chip, pin, PTP_PF_EXTTS, on);
- if (on) {
- func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
-
- err = mv88e6352_set_gpio_func(chip, pin, func, true);
- if (err)
- goto out;
-
+ if (!on) {
+ /* Always cancel the work, even if an error occurs */
+ cancel_delayed_work_sync(&chip->tai_event_work);
+ } else if (!err) {
schedule_delayed_work(&chip->tai_event_work,
TAI_EVENT_WORK_INTERVAL);
err = mv88e6352_config_eventcap(chip, rising);
- } else {
- func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO;
-
- err = mv88e6352_set_gpio_func(chip, pin, func, true);
-
- cancel_delayed_work_sync(&chip->tai_event_work);
}
-out:
mv88e6xxx_reg_unlock(chip);
return err;
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 12/20] net: dsa: mv88e6xxx: move EXTTS flag validation and pin lookup
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (10 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 11/20] net: dsa: mv88e6xxx: split out EXTTS pin setup Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 17:39 ` [PATCH RFC net-next 13/20] net: dsa: mv88e6xxx: convert to marvell TAI Russell King (Oracle)
` (7 subsequent siblings)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Move the flag validation and pin lookup to mv88e6xxx_ptp_enable()
mv88e6352_ptp_enable_extts().
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.h | 2 +-
drivers/net/dsa/mv88e6xxx/ptp.c | 29 +++++++++++++++--------------
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index ae56a88ca1c5..fe4a618c8ddd 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -732,7 +732,7 @@ struct mv88e6xxx_avb_ops {
struct mv88e6xxx_ptp_ops {
u64 (*clock_read)(struct mv88e6xxx_chip *chip);
int (*ptp_enable_extts)(struct mv88e6xxx_chip *chip,
- struct ptp_clock_request *rq, int on);
+ struct ptp_clock_request *rq, int pin, int on);
int (*ptp_verify)(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan);
void (*event_work)(struct work_struct *ugly);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 19ccc8cda1f0..efaefca1eef1 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -324,11 +324,23 @@ static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *req, int enable)
{
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+ int pin;
if (req->type != PTP_CLK_REQ_EXTTS)
return -EOPNOTSUPP;
- return chip->info->ops->ptp_ops->ptp_enable_extts(chip, req, enable);
+ /* Reject requests to enable time stamping on both edges. */
+ if (req->extts.flags & PTP_STRICT_FLAGS &&
+ req->extts.flags & PTP_ENABLE_FEATURE &&
+ (req->extts.flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES)
+ return -EOPNOTSUPP;
+
+ pin = ptp_find_pin(chip->ptp_clock, PTP_PF_EXTTS, req->extts.index);
+ if (pin < 0)
+ return -EBUSY;
+
+ return chip->info->ops->ptp_ops->ptp_enable_extts(chip, req, pin,
+ enable);
}
static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
@@ -347,24 +359,13 @@ static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
}
static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
- struct ptp_clock_request *rq, int on)
+ struct ptp_clock_request *rq, int pin,
+ int on)
{
int rising = (rq->extts.flags & PTP_RISING_EDGE);
int func;
- int pin;
int err;
- /* Reject requests to enable time stamping on both edges. */
- if ((rq->extts.flags & PTP_STRICT_FLAGS) &&
- (rq->extts.flags & PTP_ENABLE_FEATURE) &&
- (rq->extts.flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES)
- return -EOPNOTSUPP;
-
- pin = ptp_find_pin(chip->ptp_clock, PTP_PF_EXTTS, rq->extts.index);
-
- if (pin < 0)
- return -EBUSY;
-
mv88e6xxx_reg_lock(chip);
err = mv88e6352_ptp_pin_setup(chip, pin, PTP_PF_EXTTS, on);
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 13/20] net: dsa: mv88e6xxx: convert to marvell TAI
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (11 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 12/20] net: dsa: mv88e6xxx: move EXTTS flag validation and pin lookup Russell King (Oracle)
@ 2025-09-18 17:39 ` Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 14/20] net: dsa: mv88e6xxx: convert mv88e6xxx_cc_coeffs to marvell_tai_param Russell King (Oracle)
` (6 subsequent siblings)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:39 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Convert Marvell PTP timekeeping to use the Marvell PTP library TAI
implementation which is functionally identical (and was derived from
the mv88e6xxx code.)
Unfortunately, there is no progressive way to switch this over.
Note that the Marvell PTP TAI library has to be initialised without
the mv88e6xxx lock held, so we split the initialisation into two
parts.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/Kconfig | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 6 +
drivers/net/dsa/mv88e6xxx/chip.h | 26 +-
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 14 +-
drivers/net/dsa/mv88e6xxx/ptp.c | 473 ++++++++++-----------------
drivers/net/dsa/mv88e6xxx/ptp.h | 30 +-
6 files changed, 194 insertions(+), 356 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig
index 64ae3882d17c..595ca6cd6075 100644
--- a/drivers/net/dsa/mv88e6xxx/Kconfig
+++ b/drivers/net/dsa/mv88e6xxx/Kconfig
@@ -14,6 +14,7 @@ config NET_DSA_MV88E6XXX_PTP
default n
depends on (NET_DSA_MV88E6XXX = y && PTP_1588_CLOCK = y) || \
(NET_DSA_MV88E6XXX = m && PTP_1588_CLOCK)
+ select PTP_1588_CLOCK_MARVELL
help
Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
chips that support it.
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index b4d48997bf46..ed170a6b0672 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -4109,6 +4109,12 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
if (err)
goto out_hwtstamp;
+ if (chip->info->ptp_support) {
+ err = mv88e6xxx_ptp_setup_unlocked(chip);
+ if (err)
+ goto out_hwtstamp;
+ }
+
/* Have to be called without holding the register lock, since
* they take the devlink lock, and we later take the locks in
* the reverse order when getting/setting parameters or
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index fe4a618c8ddd..29543f9312bd 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -14,6 +14,7 @@
#include <linux/gpio/consumer.h>
#include <linux/kthread.h>
#include <linux/leds.h>
+#include <linux/marvell_ptp.h>
#include <linux/phy.h>
#include <linux/property.h>
#include <linux/ptp_clock_kernel.h>
@@ -412,17 +413,8 @@ struct mv88e6xxx_chip {
/* GPIO resources */
u8 gpio_data[2];
- /* This cyclecounter abstracts the switch PTP time.
- * reg_lock must be held for any operation that read()s.
- */
- struct cyclecounter tstamp_cc;
- struct timecounter tstamp_tc;
- struct delayed_work overflow_work;
- const struct mv88e6xxx_cc_coeffs *cc_coeffs;
-
- struct ptp_clock *ptp_clock;
- struct ptp_clock_info ptp_clock_info;
- struct delayed_work tai_event_work;
+ struct marvell_tai *tai;
+
struct ptp_pin_desc pin_config[MV88E6XXX_MAX_GPIO];
u16 enable_count;
@@ -446,6 +438,13 @@ struct mv88e6xxx_chip {
DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
};
+static inline struct mv88e6xxx_chip *dev_to_chip(struct device *dev)
+{
+ struct dsa_switch *ds = dev_get_drvdata(dev);
+
+ return ds->priv;
+}
+
struct mv88e6xxx_bus_ops {
int (*read)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
int (*write)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
@@ -731,11 +730,10 @@ struct mv88e6xxx_avb_ops {
struct mv88e6xxx_ptp_ops {
u64 (*clock_read)(struct mv88e6xxx_chip *chip);
- int (*ptp_enable_extts)(struct mv88e6xxx_chip *chip,
- struct ptp_clock_request *rq, int pin, int on);
+ int (*ptp_pin_setup)(struct mv88e6xxx_chip *chip, int pin,
+ enum ptp_pin_function func, int enable);
int (*ptp_verify)(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan);
- void (*event_work)(struct work_struct *ugly);
int (*port_enable)(struct mv88e6xxx_chip *chip, int port);
int (*port_disable)(struct mv88e6xxx_chip *chip, int port);
int (*global_enable)(struct mv88e6xxx_chip *chip);
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index ba989d699113..0a56e7bcbcd9 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -79,7 +79,7 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
- info->phc_index = ptp_clock_index(chip->ptp_clock);
+ info->phc_index = marvell_tai_ptp_clock_index(chip->tai);
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
@@ -289,9 +289,7 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
if (mv88e6xxx_ts_valid(status) && seq_match(skb, seq_id)) {
ns = timehi << 16 | timelo;
- mv88e6xxx_reg_lock(chip);
- ns = timecounter_cyc2time(&chip->tstamp_tc, ns);
- mv88e6xxx_reg_unlock(chip);
+ ns = marvell_tai_cyc2time(chip->tai, ns);
shwt = skb_hwtstamps(skb);
memset(shwt, 0, sizeof(*shwt));
shwt->hwtstamp = ns_to_ktime(ns);
@@ -348,7 +346,7 @@ bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
else
skb_queue_tail(&ps->rx_queue, skb);
- ptp_schedule_worker(chip->ptp_clock, 0);
+ marvell_tai_schedule(chip->tai, 0);
return true;
}
@@ -409,9 +407,7 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
time_raw = ((u32)departure_block[2] << 16) | departure_block[1];
- mv88e6xxx_reg_lock(chip);
- ns = timecounter_cyc2time(&chip->tstamp_tc, time_raw);
- mv88e6xxx_reg_unlock(chip);
+ ns = marvell_tai_cyc2time(chip->tai, time_raw);
shhwtstamps.hwtstamp = ns_to_ktime(ns);
dev_dbg(chip->dev,
@@ -490,7 +486,7 @@ void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
ps->tx_tstamp_start = jiffies;
ps->tx_seq_id = be16_to_cpu(hdr->sequence_id);
- ptp_schedule_worker(chip->ptp_clock, 0);
+ marvell_tai_schedule(chip->tai, 0);
}
int mv88e6165_global_disable(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index efaefca1eef1..87a45dc6b811 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -16,8 +16,6 @@
#include "hwtstamp.h"
#include "ptp.h"
-#define MV88E6XXX_MAX_ADJ_PPB 1000000
-
struct mv88e6xxx_cc_coeffs {
u32 cc_shift;
u32 cc_mult;
@@ -70,14 +68,6 @@ static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_4ns_coeffs = {
.cc_mult_dem = 15625ULL
};
-#define TAI_EVENT_WORK_INTERVAL msecs_to_jiffies(100)
-
-#define cc_to_chip(cc) container_of(cc, struct mv88e6xxx_chip, tstamp_cc)
-#define dw_overflow_to_chip(dw) container_of(dw, struct mv88e6xxx_chip, \
- overflow_work)
-#define dw_tai_event_to_chip(dw) container_of(dw, struct mv88e6xxx_chip, \
- tai_event_work)
-
static int mv88e6xxx_tai_read(struct mv88e6xxx_chip *chip, int addr,
u16 *data, int len)
{
@@ -87,14 +77,141 @@ static int mv88e6xxx_tai_read(struct mv88e6xxx_chip *chip, int addr,
return chip->info->ops->avb_ops->tai_read(chip, addr, data, len);
}
-static int mv88e6xxx_tai_write(struct mv88e6xxx_chip *chip, int addr, u16 data)
+static int mv88e6xxx_tai_hw_enable(struct device *dev)
{
- if (!chip->info->ops->avb_ops->tai_write)
- return -EOPNOTSUPP;
+ return 0;
+}
+
+static void mv88e6xxx_tai_hw_disable(struct device *dev)
+{
+}
+
+static u64 mv88e6xxx_tai_clock_read(struct device *dev,
+ struct ptp_system_timestamp *sts)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ const struct mv88e6xxx_ptp_ops *ptp_ops;
+ u64 val = 0;
+
+ ptp_ops = chip->info->ops->ptp_ops;
+
+ if (chip->info->ops->ptp_ops->clock_read) {
+ mv88e6xxx_reg_lock(chip);
+ ptp_read_system_prets(sts);
+ val = ptp_ops->clock_read(chip);
+ ptp_read_system_postts(sts);
+ mv88e6xxx_reg_unlock(chip);
+ }
+
+ return val;
+}
+
+static int mv88e6xxx_tai_extts_read(struct device *dev, int reg,
+ struct marvell_extts *extts)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ const struct mv88e6xxx_avb_ops *avb_ops;
+ u16 regs[3];
+ int ret;
+
+ avb_ops = chip->info->ops->avb_ops;
+
+ mv88e6xxx_reg_lock(chip);
+ ret = avb_ops->tai_read(chip, reg, regs, 3);
+ if (ret < 0)
+ goto unlock;
+
+ extts->status = regs[0];
+ extts->time = regs[1] | regs[2] << 16;
+
+ /* Clear valid if set */
+ if (regs[0] & MV_STATUS_EVENTCAPVALID) {
+ avb_ops->tai_write(chip, reg, 0);
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+unlock:
+ mv88e6xxx_reg_unlock(chip);
+
+ return ret;
+}
+
+static int mv88e6xxx_tai_pin_verify(struct device *dev, int pin,
+ enum ptp_pin_function func,
+ unsigned int chan)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
- return chip->info->ops->avb_ops->tai_write(chip, addr, data);
+ return chip->info->ops->ptp_ops->ptp_verify(chip, pin, func, chan);
}
+static int mv88e6xxx_tai_pin_setup(struct device *dev, int pin,
+ enum ptp_pin_function func, int enable)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ int err;
+
+ mv88e6xxx_reg_lock(chip);
+ err = chip->info->ops->ptp_ops->ptp_pin_setup(chip, pin, func, enable);
+ mv88e6xxx_reg_unlock(chip);
+
+ return err;
+}
+
+static int mv88e6xxx_tai_write(struct device *dev, u8 reg, u16 val)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ int err;
+
+ mv88e6xxx_reg_lock(chip);
+ err = chip->info->ops->avb_ops->tai_write(chip, reg, val);
+ mv88e6xxx_reg_unlock(chip);
+
+ return err;
+}
+
+static int mv88e6xxx_tai_modify(struct device *dev, u8 reg, u16 mask, u16 val)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ const struct mv88e6xxx_avb_ops *avb_ops;
+ u16 old, new;
+ int err;
+
+ avb_ops = chip->info->ops->avb_ops;
+
+ mv88e6xxx_reg_lock(chip);
+ err = avb_ops->tai_read(chip, reg, &old, 1);
+ if (err < 0)
+ goto unlock;
+
+ new = (old & ~mask) | val;
+ if (new != old)
+ err = avb_ops->tai_write(chip, reg, new);
+
+unlock:
+ mv88e6xxx_reg_unlock(chip);
+ return err;
+}
+
+static long mv88e6xxx_tai_aux_work(struct device *dev)
+{
+ return mv88e6xxx_hwtstamp_work(dev_to_chip(dev));
+}
+
+static const struct marvell_tai_ops mv88e6xxx_tai_ops = {
+ .tai_hw_enable = mv88e6xxx_tai_hw_enable,
+ .tai_hw_disable = mv88e6xxx_tai_hw_disable,
+ .tai_clock_read = mv88e6xxx_tai_clock_read,
+ .tai_extts_read = mv88e6xxx_tai_extts_read,
+ .tai_pin_verify = mv88e6xxx_tai_pin_verify,
+ .tai_pin_setup = mv88e6xxx_tai_pin_setup,
+ .tai_write = mv88e6xxx_tai_write,
+ .tai_modify = mv88e6xxx_tai_modify,
+ .tai_aux_work = mv88e6xxx_tai_aux_work,
+};
+
/* TODO: places where this are called should be using pinctrl */
static int mv88e6352_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
int func, int input)
@@ -178,212 +295,6 @@ static u64 mv88e6165_ptp_clock_read(struct mv88e6xxx_chip *chip)
return ((u32)phc_time[1] << 16) | phc_time[0];
}
-/* mv88e6352_config_eventcap - configure TAI event capture
- * @rising: zero for falling-edge trigger, else rising-edge trigger
- *
- * This will also reset the capture sequence counter.
- */
-static int mv88e6352_config_eventcap(struct mv88e6xxx_chip *chip, int rising)
-{
- u16 evcap_config;
- int err;
-
- evcap_config = MV88E6352_TAI_CFG_CAP_OVERWRITE |
- MV88E6352_TAI_CFG_CAP_CTR_START;
- if (!rising)
- evcap_config |= MV88E6352_TAI_CFG_EVREQ_FALLING;
-
- err = mv88e6xxx_tai_write(chip, MV88E6352_TAI_CFG, evcap_config);
- if (err)
- return err;
-
- /* Write the capture config; this also clears the capture counter */
- return mv88e6xxx_tai_write(chip, MV88E6352_TAI_EVENT_STATUS, 0);
-}
-
-static void mv88e6352_tai_event_work(struct work_struct *ugly)
-{
- struct delayed_work *dw = to_delayed_work(ugly);
- struct mv88e6xxx_chip *chip = dw_tai_event_to_chip(dw);
- struct ptp_clock_event ev;
- u16 status[4];
- u32 raw_ts;
- int err;
-
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_tai_read(chip, MV88E6352_TAI_EVENT_STATUS,
- status, ARRAY_SIZE(status));
- mv88e6xxx_reg_unlock(chip);
-
- if (err) {
- dev_err(chip->dev, "failed to read TAI status register\n");
- return;
- }
- if (status[0] & MV88E6352_TAI_EVENT_STATUS_ERROR) {
- dev_warn(chip->dev, "missed event capture\n");
- return;
- }
- if (!(status[0] & MV88E6352_TAI_EVENT_STATUS_VALID))
- goto out;
-
- raw_ts = ((u32)status[2] << 16) | status[1];
-
- /* Clear the valid bit so the next timestamp can come in */
- status[0] &= ~MV88E6352_TAI_EVENT_STATUS_VALID;
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_tai_write(chip, MV88E6352_TAI_EVENT_STATUS, status[0]);
- mv88e6xxx_reg_unlock(chip);
- if (err) {
- dev_err(chip->dev, "failed to write TAI status register\n");
- return;
- }
-
- /* This is an external timestamp */
- ev.type = PTP_CLOCK_EXTTS;
-
- /* We only have one timestamping channel. */
- ev.index = 0;
- mv88e6xxx_reg_lock(chip);
- ev.timestamp = timecounter_cyc2time(&chip->tstamp_tc, raw_ts);
- mv88e6xxx_reg_unlock(chip);
-
- ptp_clock_event(chip->ptp_clock, &ev);
-out:
- schedule_delayed_work(&chip->tai_event_work, TAI_EVENT_WORK_INTERVAL);
-}
-
-static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
-{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
- int neg_adj = 0;
- u32 diff, mult;
- u64 adj;
-
- if (scaled_ppm < 0) {
- neg_adj = 1;
- scaled_ppm = -scaled_ppm;
- }
-
- mult = chip->cc_coeffs->cc_mult;
- adj = chip->cc_coeffs->cc_mult_num;
- adj *= scaled_ppm;
- diff = div_u64(adj, chip->cc_coeffs->cc_mult_dem);
-
- mv88e6xxx_reg_lock(chip);
-
- timecounter_read(&chip->tstamp_tc);
- chip->tstamp_cc.mult = neg_adj ? mult - diff : mult + diff;
-
- mv88e6xxx_reg_unlock(chip);
-
- return 0;
-}
-
-static int mv88e6xxx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
-{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
-
- mv88e6xxx_reg_lock(chip);
- timecounter_adjtime(&chip->tstamp_tc, delta);
- mv88e6xxx_reg_unlock(chip);
-
- return 0;
-}
-
-static int mv88e6xxx_ptp_gettime(struct ptp_clock_info *ptp,
- struct timespec64 *ts)
-{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
- u64 ns;
-
- mv88e6xxx_reg_lock(chip);
- ns = timecounter_read(&chip->tstamp_tc);
- mv88e6xxx_reg_unlock(chip);
-
- *ts = ns_to_timespec64(ns);
-
- return 0;
-}
-
-static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
- const struct timespec64 *ts)
-{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
- u64 ns;
-
- ns = timespec64_to_ns(ts);
-
- mv88e6xxx_reg_lock(chip);
- timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ns);
- mv88e6xxx_reg_unlock(chip);
-
- return 0;
-}
-
-static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
- struct ptp_clock_request *req, int enable)
-{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
- int pin;
-
- if (req->type != PTP_CLK_REQ_EXTTS)
- return -EOPNOTSUPP;
-
- /* Reject requests to enable time stamping on both edges. */
- if (req->extts.flags & PTP_STRICT_FLAGS &&
- req->extts.flags & PTP_ENABLE_FEATURE &&
- (req->extts.flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES)
- return -EOPNOTSUPP;
-
- pin = ptp_find_pin(chip->ptp_clock, PTP_PF_EXTTS, req->extts.index);
- if (pin < 0)
- return -EBUSY;
-
- return chip->info->ops->ptp_ops->ptp_enable_extts(chip, req, pin,
- enable);
-}
-
-static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
- enum ptp_pin_function func, unsigned int chan)
-{
- struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
-
- /* Always allow a pin to be set to no function */
- if (func == PTP_PF_NONE)
- return 0;
-
- if (func != PTP_PF_EXTTS)
- return -EOPNOTSUPP;
-
- return chip->info->ops->ptp_ops->ptp_verify(chip, pin, func, chan);
-}
-
-static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
- struct ptp_clock_request *rq, int pin,
- int on)
-{
- int rising = (rq->extts.flags & PTP_RISING_EDGE);
- int func;
- int err;
-
- mv88e6xxx_reg_lock(chip);
- err = mv88e6352_ptp_pin_setup(chip, pin, PTP_PF_EXTTS, on);
-
- if (!on) {
- /* Always cancel the work, even if an error occurs */
- cancel_delayed_work_sync(&chip->tai_event_work);
- } else if (!err) {
- schedule_delayed_work(&chip->tai_event_work,
- TAI_EVENT_WORK_INTERVAL);
-
- err = mv88e6352_config_eventcap(chip, rising);
- }
-
- mv88e6xxx_reg_unlock(chip);
-
- return err;
-}
-
static int mv88e6352_ptp_verify(struct mv88e6xxx_chip *chip, unsigned int pin,
enum ptp_pin_function func, unsigned int chan)
{
@@ -408,9 +319,8 @@ const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
.clock_read = mv88e6352_ptp_clock_read,
- .ptp_enable_extts = mv88e6352_ptp_enable_extts,
+ .ptp_pin_setup = mv88e6352_ptp_pin_setup,
.ptp_verify = mv88e6352_ptp_verify,
- .event_work = mv88e6352_tai_event_work,
.port_enable = mv88e6352_hwtstamp_port_enable,
.port_disable = mv88e6352_hwtstamp_port_disable,
.n_ext_ts = 1,
@@ -431,9 +341,8 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = {
.clock_read = mv88e6352_ptp_clock_read,
- .ptp_enable_extts = mv88e6352_ptp_enable_extts,
+ .ptp_pin_setup = mv88e6352_ptp_pin_setup,
.ptp_verify = mv88e6352_ptp_verify,
- .event_work = mv88e6352_tai_event_work,
.port_enable = mv88e6352_hwtstamp_port_enable,
.port_disable = mv88e6352_hwtstamp_port_disable,
.set_ptp_cpu_port = mv88e6390_g1_set_ptp_cpu_port,
@@ -474,114 +383,60 @@ static int mv88e6xxx_set_ptp_cpu_port(struct mv88e6xxx_chip *chip)
return err;
}
-static u64 mv88e6xxx_ptp_clock_read(struct cyclecounter *cc)
-{
- struct mv88e6xxx_chip *chip = cc_to_chip(cc);
-
- if (chip->info->ops->ptp_ops->clock_read)
- return chip->info->ops->ptp_ops->clock_read(chip);
-
- return 0;
-}
-
-/* With a 250MHz input clock, the 32-bit timestamp counter overflows in ~17.2
- * seconds; this task forces periodic reads so that we don't miss any.
- */
-#define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 8)
-static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
-{
- struct delayed_work *dw = to_delayed_work(work);
- struct mv88e6xxx_chip *chip = dw_overflow_to_chip(dw);
- struct timespec64 ts;
-
- mv88e6xxx_ptp_gettime(&chip->ptp_clock_info, &ts);
-
- schedule_delayed_work(&chip->overflow_work,
- MV88E6XXX_TAI_OVERFLOW_PERIOD);
-}
-
-static long mv88e6xxx_ptp_aux_work(struct ptp_clock_info *ptp)
-{
- return mv88e6xxx_hwtstamp_work(ptp_to_chip(ptp));
-}
-
int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
- int err, i;
+ const struct mv88e6xxx_cc_coeffs *cc_coeffs;
+ struct marvell_tai_param tai_param;
+ struct marvell_tai_pins pins;
+ int i, err;
/* Set up the cycle counter */
- chip->cc_coeffs = mv88e6xxx_cc_coeff_get(chip);
- if (IS_ERR(chip->cc_coeffs))
- return PTR_ERR(chip->cc_coeffs);
-
- memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc));
- chip->tstamp_cc.read = mv88e6xxx_ptp_clock_read;
- chip->tstamp_cc.mask = CYCLECOUNTER_MASK(32);
- chip->tstamp_cc.mult = chip->cc_coeffs->cc_mult;
- chip->tstamp_cc.shift = chip->cc_coeffs->cc_shift;
+ cc_coeffs = mv88e6xxx_cc_coeff_get(chip);
+ if (IS_ERR(cc_coeffs))
+ return PTR_ERR(cc_coeffs);
- timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc,
- ktime_to_ns(ktime_get_real()));
+ err = mv88e6xxx_set_ptp_cpu_port(chip);
+ if (err)
+ return err;
- INIT_DELAYED_WORK(&chip->overflow_work, mv88e6xxx_ptp_overflow_check);
- if (ptp_ops->event_work)
- INIT_DELAYED_WORK(&chip->tai_event_work, ptp_ops->event_work);
+ mv88e6xxx_reg_unlock(chip);
- chip->ptp_clock_info.owner = THIS_MODULE;
- snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name),
- "%s", dev_name(chip->dev));
+ memset(&tai_param, 0, sizeof(tai_param));
+ tai_param.cc_mult_num = cc_coeffs->cc_mult_num;
+ tai_param.cc_mult_den = cc_coeffs->cc_mult_dem;
+ tai_param.cc_mult = cc_coeffs->cc_mult;
+ tai_param.cc_shift = cc_coeffs->cc_shift;
- chip->ptp_clock_info.n_ext_ts = ptp_ops->n_ext_ts;
- chip->ptp_clock_info.n_per_out = 0;
- chip->ptp_clock_info.n_pins = mv88e6xxx_num_gpio(chip);
- chip->ptp_clock_info.pps = 0;
+ memset(&pins, 0, sizeof(pins));
+ pins.n_ext_ts = ptp_ops->n_ext_ts;
+ pins.n_pins = mv88e6xxx_num_gpio(chip);
+ pins.pins = chip->pin_config;
+ pins.supported_extts_flags = PTP_EXTTS_EDGES;
- for (i = 0; i < chip->ptp_clock_info.n_pins; ++i) {
+ for (i = 0; i < pins.n_pins; ++i) {
struct ptp_pin_desc *ppd = &chip->pin_config[i];
snprintf(ppd->name, sizeof(ppd->name), "mv88e6xxx_gpio%d", i);
ppd->index = i;
ppd->func = PTP_PF_NONE;
}
- chip->ptp_clock_info.pin_config = chip->pin_config;
- chip->ptp_clock_info.max_adj = MV88E6XXX_MAX_ADJ_PPB;
- chip->ptp_clock_info.adjfine = mv88e6xxx_ptp_adjfine;
- chip->ptp_clock_info.adjtime = mv88e6xxx_ptp_adjtime;
- chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime;
- chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime;
- chip->ptp_clock_info.enable = mv88e6xxx_ptp_enable;
- chip->ptp_clock_info.verify = mv88e6xxx_ptp_verify;
- chip->ptp_clock_info.do_aux_work = mv88e6xxx_ptp_aux_work;
-
- chip->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE |
- PTP_FALLING_EDGE |
- PTP_STRICT_FLAGS;
-
- err = mv88e6xxx_set_ptp_cpu_port(chip);
- if (err)
- return err;
-
- chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev);
- if (IS_ERR(chip->ptp_clock))
- return PTR_ERR(chip->ptp_clock);
+ err = marvell_tai_probe(&chip->tai, &mv88e6xxx_tai_ops, &tai_param,
+ &pins, dev_name(chip->dev), chip->dev);
+ mv88e6xxx_reg_lock(chip);
- schedule_delayed_work(&chip->overflow_work,
- MV88E6XXX_TAI_OVERFLOW_PERIOD);
+ return err;
+}
+int mv88e6xxx_ptp_setup_unlocked(struct mv88e6xxx_chip *chip)
+{
return 0;
}
/* This must never be called holding the register lock */
void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
{
- if (chip->ptp_clock) {
- cancel_delayed_work_sync(&chip->overflow_work);
- if (chip->info->ops->ptp_ops->event_work)
- cancel_delayed_work_sync(&chip->tai_event_work);
-
- ptp_clock_unregister(chip->ptp_clock);
- chip->ptp_clock = NULL;
- }
+ if (chip->tai)
+ marvell_tai_remove(chip->tai);
}
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
index 95bdddb0bf39..1e598038acf1 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.h
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -15,39 +15,15 @@
#include "chip.h"
-/* Offset 0x00: TAI Global Config */
-#define MV88E6352_TAI_CFG 0x00
-#define MV88E6352_TAI_CFG_CAP_OVERWRITE 0x8000
-#define MV88E6352_TAI_CFG_CAP_CTR_START 0x4000
-#define MV88E6352_TAI_CFG_EVREQ_FALLING 0x2000
-#define MV88E6352_TAI_CFG_TRIG_ACTIVE_LO 0x1000
-#define MV88E6352_TAI_CFG_IRL_ENABLE 0x0400
-#define MV88E6352_TAI_CFG_TRIG_IRQ_EN 0x0200
-#define MV88E6352_TAI_CFG_EVREQ_IRQ_EN 0x0100
-#define MV88E6352_TAI_CFG_TRIG_LOCK 0x0080
-#define MV88E6352_TAI_CFG_BLOCK_UPDATE 0x0008
-#define MV88E6352_TAI_CFG_MULTI_PTP 0x0004
-#define MV88E6352_TAI_CFG_TRIG_MODE_ONESHOT 0x0002
-#define MV88E6352_TAI_CFG_TRIG_ENABLE 0x0001
-
/* Offset 0x01: Timestamp Clock Period (ps) */
#define MV88E6XXX_TAI_CLOCK_PERIOD 0x01
-/* Offset 0x09: Event Status */
-#define MV88E6352_TAI_EVENT_STATUS 0x09
-#define MV88E6352_TAI_EVENT_STATUS_ERROR 0x0200
-#define MV88E6352_TAI_EVENT_STATUS_VALID 0x0100
-#define MV88E6352_TAI_EVENT_STATUS_CTR_MASK 0x00ff
-/* Offset 0x0A/0x0B: Event Time Lo/Hi. Always read with Event Status. */
-
/* Offset 0x0E/0x0F: PTP Global Time */
#define MV88E6352_TAI_TIME_LO 0x0e
-#define MV88E6352_TAI_TIME_HI 0x0f
/* 6165 Global Control Registers */
/* Offset 0x9/0xa: Global Time */
#define MV88E6165_PTP_GC_TIME_LO 0x09
-#define MV88E6165_PTP_GC_TIME_HI 0x0A
/* 6165 Per Port Registers. The arrival and departure registers are a
* common block consisting of status, two time registers and the sequence ID
@@ -67,6 +43,7 @@
#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip);
+int mv88e6xxx_ptp_setup_unlocked(struct mv88e6xxx_chip *chip);
void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip);
#define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip, \
@@ -83,6 +60,11 @@ static inline int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
return 0;
}
+static inline int mv88e6xxx_ptp_setup_unlocked(struct mv88e6xxx_chip *chip)
+{
+ return 0;
+}
+
static inline void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
{
}
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 14/20] net: dsa: mv88e6xxx: convert mv88e6xxx_cc_coeffs to marvell_tai_param
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (12 preceding siblings ...)
2025-09-18 17:39 ` [PATCH RFC net-next 13/20] net: dsa: mv88e6xxx: convert to marvell TAI Russell King (Oracle)
@ 2025-09-18 17:40 ` Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 15/20] net: dsa: mv88e6xxx: allow generic core to configure global regs Russell King (Oracle)
` (5 subsequent siblings)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:40 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Convert the coefficients to struct marvell_tai_param.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/ptp.c | 40 +++++++++++----------------------
1 file changed, 13 insertions(+), 27 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 87a45dc6b811..acd17380e7ea 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -16,13 +16,6 @@
#include "hwtstamp.h"
#include "ptp.h"
-struct mv88e6xxx_cc_coeffs {
- u32 cc_shift;
- u32 cc_mult;
- u32 cc_mult_num;
- u32 cc_mult_dem;
-};
-
/* Family MV88E6250:
* Raw timestamps are in units of 10-ns clock periods.
*
@@ -31,11 +24,11 @@ struct mv88e6xxx_cc_coeffs {
* clkadj = scaled_ppm * 2^7 / 5^5
*/
#define MV88E6XXX_CC_10NS_SHIFT 28
-static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_10ns_coeffs = {
+static const struct marvell_tai_param mv88e6xxx_cc_10ns_coeffs = {
.cc_shift = MV88E6XXX_CC_10NS_SHIFT,
.cc_mult = 10 << MV88E6XXX_CC_10NS_SHIFT,
.cc_mult_num = 1 << 7,
- .cc_mult_dem = 3125ULL,
+ .cc_mult_den = 3125ULL,
};
/* Other families except MV88E6393X in internal clock mode:
@@ -46,11 +39,11 @@ static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_10ns_coeffs = {
* clkadj = scaled_ppm * 2^9 / 5^6
*/
#define MV88E6XXX_CC_8NS_SHIFT 28
-static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_8ns_coeffs = {
+static const struct marvell_tai_param mv88e6xxx_cc_8ns_coeffs = {
.cc_shift = MV88E6XXX_CC_8NS_SHIFT,
.cc_mult = 8 << MV88E6XXX_CC_8NS_SHIFT,
.cc_mult_num = 1 << 9,
- .cc_mult_dem = 15625ULL
+ .cc_mult_den = 15625ULL
};
/* Family MV88E6393X using internal clock:
@@ -61,11 +54,11 @@ static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_8ns_coeffs = {
* clkadj = scaled_ppm * 2^8 / 5^6
*/
#define MV88E6XXX_CC_4NS_SHIFT 28
-static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_4ns_coeffs = {
+static const struct marvell_tai_param mv88e6xxx_cc_4ns_coeffs = {
.cc_shift = MV88E6XXX_CC_4NS_SHIFT,
.cc_mult = 4 << MV88E6XXX_CC_4NS_SHIFT,
.cc_mult_num = 1 << 8,
- .cc_mult_dem = 15625ULL
+ .cc_mult_den = 15625ULL
};
static int mv88e6xxx_tai_read(struct mv88e6xxx_chip *chip, int addr,
@@ -242,8 +235,8 @@ static int mv88e6352_ptp_pin_setup(struct mv88e6xxx_chip *chip, int pin,
return mv88e6352_set_gpio_func(chip, pin, func, true);
}
-static const struct mv88e6xxx_cc_coeffs *
-mv88e6xxx_cc_coeff_get(struct mv88e6xxx_chip *chip)
+static const struct marvell_tai_param *
+mv88e6xxx_tai_param_get(struct mv88e6xxx_chip *chip)
{
u16 period_ps;
int err;
@@ -386,15 +379,14 @@ static int mv88e6xxx_set_ptp_cpu_port(struct mv88e6xxx_chip *chip)
int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
- const struct mv88e6xxx_cc_coeffs *cc_coeffs;
- struct marvell_tai_param tai_param;
+ const struct marvell_tai_param *tai_param;
struct marvell_tai_pins pins;
int i, err;
/* Set up the cycle counter */
- cc_coeffs = mv88e6xxx_cc_coeff_get(chip);
- if (IS_ERR(cc_coeffs))
- return PTR_ERR(cc_coeffs);
+ tai_param = mv88e6xxx_tai_param_get(chip);
+ if (IS_ERR(tai_param))
+ return PTR_ERR(tai_param);
err = mv88e6xxx_set_ptp_cpu_port(chip);
if (err)
@@ -402,12 +394,6 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
mv88e6xxx_reg_unlock(chip);
- memset(&tai_param, 0, sizeof(tai_param));
- tai_param.cc_mult_num = cc_coeffs->cc_mult_num;
- tai_param.cc_mult_den = cc_coeffs->cc_mult_dem;
- tai_param.cc_mult = cc_coeffs->cc_mult;
- tai_param.cc_shift = cc_coeffs->cc_shift;
-
memset(&pins, 0, sizeof(pins));
pins.n_ext_ts = ptp_ops->n_ext_ts;
pins.n_pins = mv88e6xxx_num_gpio(chip);
@@ -422,7 +408,7 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
ppd->func = PTP_PF_NONE;
}
- err = marvell_tai_probe(&chip->tai, &mv88e6xxx_tai_ops, &tai_param,
+ err = marvell_tai_probe(&chip->tai, &mv88e6xxx_tai_ops, tai_param,
&pins, dev_name(chip->dev), chip->dev);
mv88e6xxx_reg_lock(chip);
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 15/20] net: dsa: mv88e6xxx: allow generic core to configure global regs
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (13 preceding siblings ...)
2025-09-18 17:40 ` [PATCH RFC net-next 14/20] net: dsa: mv88e6xxx: convert mv88e6xxx_cc_coeffs to marvell_tai_param Russell King (Oracle)
@ 2025-09-18 17:40 ` Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 16/20] net: dsa: mv88e6xxx: add beginnings of generic Marvell PTP ts layer Russell King (Oracle)
` (4 subsequent siblings)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:40 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 0a56e7bcbcd9..dc92381d5c07 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -544,6 +544,17 @@ static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
return 0;
}
+static int mv88e6xxx_ts_global_write(struct device *dev, u8 reg, u16 val)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+
+ return chip->info->ops->avb_ops->ptp_write(chip, reg, val);
+}
+
+static const struct marvell_ts_ops mv88e6xxx_ts_ops = {
+ .ts_global_write = mv88e6xxx_ts_global_write,
+};
+
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
@@ -564,8 +575,7 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
return err;
}
- /* Set the ethertype of L2 PTP messages */
- err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_ETHERTYPE, ETH_P_1588);
+ err = marvell_ts_global_config(chip->dev, &mv88e6xxx_ts_ops);
if (err)
return err;
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 16/20] net: dsa: mv88e6xxx: add beginnings of generic Marvell PTP ts layer
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (14 preceding siblings ...)
2025-09-18 17:40 ` [PATCH RFC net-next 15/20] net: dsa: mv88e6xxx: allow generic core to configure global regs Russell King (Oracle)
@ 2025-09-18 17:40 ` Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 17/20] net: dsa: mv88e6xxx: switch tx timestamping to core Russell King (Oracle)
` (3 subsequent siblings)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:40 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Initialise the generic Marvell PTP per-port timestamping layer, and
use it to provide the get_ts_info() method.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.c | 4 +
drivers/net/dsa/mv88e6xxx/chip.h | 2 +
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 188 ++++++++++++++++++++++++---
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 6 +
4 files changed, 182 insertions(+), 18 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ed170a6b0672..fcb7b542bb27 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -4113,6 +4113,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
err = mv88e6xxx_ptp_setup_unlocked(chip);
if (err)
goto out_hwtstamp;
+
+ err = mv88e6xxx_hwtstamp_setup_unlocked(chip);
+ if (err)
+ goto out_hwtstamp;
}
/* Have to be called without holding the register lock, since
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 29543f9312bd..a297b8867225 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -424,6 +424,8 @@ struct mv88e6xxx_chip {
/* Per-port timestamping resources. */
struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
+ struct marvell_ts ptp_ts[DSA_MAX_PORTS];
+ struct marvell_ts_caps ptp_caps;
/* Array of port structures. */
struct mv88e6xxx_port ports[DSA_MAX_PORTS];
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index dc92381d5c07..3e6a0481fc19 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -21,21 +21,37 @@
static int mv88e6xxx_port_ptp_read(struct mv88e6xxx_chip *chip, int port,
int addr, u16 *data, int len)
{
+ int err;
+
if (!chip->info->ops->avb_ops->port_ptp_read)
return -EOPNOTSUPP;
- return chip->info->ops->avb_ops->port_ptp_read(chip, port, addr,
+ err = chip->info->ops->avb_ops->port_ptp_read(chip, port, addr,
data, len);
+
+ dev_printk(KERN_DEBUG,
+ chip->dev, "%s: port=%d addr=%d, data[0]=%04x len=%d (%d)\n",
+ __func__, port, addr, data[0], len, err);
+
+ return err;
}
static int mv88e6xxx_port_ptp_write(struct mv88e6xxx_chip *chip, int port,
int addr, u16 data)
{
+ int err;
+
if (!chip->info->ops->avb_ops->port_ptp_write)
return -EOPNOTSUPP;
- return chip->info->ops->avb_ops->port_ptp_write(chip, port, addr,
+ err = chip->info->ops->avb_ops->port_ptp_write(chip, port, addr,
data);
+
+ dev_printk(KERN_DEBUG,
+ chip->dev, "%s: port=%d addr=%d data=%04x (%d)\n",
+ __func__, port, addr, data, err);
+
+ return err;
}
static int mv88e6xxx_ptp_write(struct mv88e6xxx_chip *chip, int addr,
@@ -66,24 +82,14 @@ static int mv88e6xxx_ptp_read(struct mv88e6xxx_chip *chip, int addr,
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct kernel_ethtool_ts_info *info)
{
- const struct mv88e6xxx_ptp_ops *ptp_ops;
struct mv88e6xxx_chip *chip;
chip = ds->priv;
- ptp_ops = chip->info->ops->ptp_ops;
if (!chip->info->ptp_support)
return -EOPNOTSUPP;
- info->so_timestamping =
- SOF_TIMESTAMPING_TX_HARDWARE |
- SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE;
- info->phc_index = marvell_tai_ptp_clock_index(chip->tai);
- info->tx_types =
- (1 << HWTSTAMP_TX_OFF) |
- (1 << HWTSTAMP_TX_ON);
- info->rx_filters = ptp_ops->rx_filters;
+ marvell_ts_info(&chip->ptp_ts[port], info);
return 0;
}
@@ -439,20 +445,31 @@ long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip)
{
struct dsa_switch *ds = chip->ds;
struct mv88e6xxx_port_hwtstamp *ps;
- int i, restart = 0;
+ long ret, delay = -1;
+ int i;
for (i = 0; i < ds->num_ports; i++) {
if (!dsa_is_user_port(ds, i))
continue;
ps = &chip->port_hwtstamp[i];
- if (test_bit(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state))
- restart |= mv88e6xxx_txtstamp_work(chip, ps);
+ if (test_bit(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state) &&
+ mv88e6xxx_txtstamp_work(chip, ps))
+ delay = 1;
mv88e6xxx_rxtstamp_work(chip, ps);
}
- return restart ? 1 : -1;
+ for (i = 0; i < ds->num_ports; i++) {
+ if (!dsa_is_user_port(ds, i))
+ continue;
+
+ ret = marvell_ts_aux_work(&chip->ptp_ts[i]);
+ if (ret >= 0 && (delay == -1 || delay > ret))
+ delay = ret;
+ }
+
+ return delay;
}
void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
@@ -551,18 +568,129 @@ static int mv88e6xxx_ts_global_write(struct device *dev, u8 reg, u16 val)
return chip->info->ops->avb_ops->ptp_write(chip, reg, val);
}
+/* The device differences are:
+ * ts_reg MV88E6165 Others
+ * TS_ARR0 MV88E6165_PORT_PTP_ARR0_STS MV88E6XXX_PORT_PTP_ARR0_STS
+ * TS_ARR1 MV88E6165_PORT_PTP_ARR1_STS MV88E6XXX_PORT_PTP_ARR1_STS
+ * TS_DEP MV88E6165_PORT_PTP_DEP_STS MV88E6XXX_PORT_PTP_DEP_STS
+ */
+static int mv88e6xxx_ts_port_read_ts(struct device *dev,
+ struct marvell_hwts *hwts, u8 port,
+ enum marvell_ts_reg ts_reg)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ u16 data[4];
+ u16 reg;
+ int ret;
+
+ switch (ts_reg) {
+ case MARVELL_TS_ARR0:
+ reg = chip->info->ops->ptp_ops->arr0_sts_reg;
+ break;
+ case MARVELL_TS_ARR1:
+ reg = chip->info->ops->ptp_ops->arr1_sts_reg;
+ break;
+ case MARVELL_TS_DEP:
+ reg = chip->info->ops->ptp_ops->dep_sts_reg;
+ break;
+ }
+
+ mv88e6xxx_reg_lock(chip);
+ /* Read the status, time and sequence registers. If there's a valid
+ * timestamp, immediately clear the status.
+ */
+ ret = mv88e6xxx_port_ptp_read(chip, port, reg, data, ARRAY_SIZE(data));
+ if (ret == 0 && data[0] & MV_STATUS_VALID)
+ ret = mv88e6xxx_port_ptp_write(chip, port, reg, 0);
+ mv88e6xxx_reg_unlock(chip);
+
+ if (ret == 0) {
+ hwts->stat = data[0];
+ hwts->time = data[1] | data[2] << 16;
+ hwts->seq = data[3];
+
+ ret = !!(hwts->stat & MV_STATUS_VALID);
+ }
+
+ return ret;
+}
+
+/* PTP_PORT_CONFIG_0 is MV88E6XXX_PORT_PTP_CFG0
+ * PTP_PORT_CONFIG_1 is MV88E6XXX_PORT_PTP_CFG1
+ * note: nothing sets this register in this driver
+ * PTP_PORT_CONFIG_2 is MV88E6XXX_PORT_PTP_CFG2
+ * note: nothing sets this register in this driver
+ * MV88E6XXX_PORT_PTP_LED_CFG has no equivalent
+ * note: nothing sets this register in this driver
+ * mv88e6165 doesn't have these registers
+ */
+static int mv88e6xxx_ts_port_write(struct device *dev, u8 port, u8 reg, u16 val)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ const struct mv88e6xxx_avb_ops *avb_ops;
+ u16 old;
+ int err;
+
+ avb_ops = chip->info->ops->avb_ops;
+
+ mv88e6xxx_reg_lock(chip);
+ err = avb_ops->port_ptp_read(chip, port, reg, &old, 1);
+ err = avb_ops->port_ptp_write(chip, port, reg, val);
+ mv88e6xxx_reg_unlock(chip);
+
+ dev_printk(KERN_DEBUG,
+ dev, "%s: port=%u reg=%u val=%04x, old=%04x (%d)\n",
+ __func__, port, reg, val, old, err);
+
+ return err;
+}
+
+static int mv88e6xxx_ts_port_modify(struct device *dev, u8 port, u8 reg,
+ u16 mask, u16 val)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ const struct mv88e6xxx_avb_ops *avb_ops;
+ u16 old, data;
+ int err;
+
+ avb_ops = chip->info->ops->avb_ops;
+
+ mv88e6xxx_reg_lock(chip);
+ err = avb_ops->port_ptp_read(chip, port, reg, &old, 1);
+ if (err)
+ goto out;
+
+ data = (old & ~mask) | val;
+ err = avb_ops->port_ptp_write(chip, port, reg, data);
+
+ dev_printk(KERN_DEBUG,
+ dev, "%s: port=%u reg=%u mask=%04x val=%04x, 0x%04x -> 0x%04x (%d)\n",
+ __func__, port, reg, mask, val, old, data, err);
+
+out:
+ mv88e6xxx_reg_unlock(chip);
+
+ return err;
+}
+
static const struct marvell_ts_ops mv88e6xxx_ts_ops = {
.ts_global_write = mv88e6xxx_ts_global_write,
+ .ts_port_read_ts = mv88e6xxx_ts_port_read_ts,
+ .ts_port_write = mv88e6xxx_ts_port_write,
+ .ts_port_modify = mv88e6xxx_ts_port_modify,
};
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
+ unsigned int n_ports = mv88e6xxx_num_ports(chip);
int err;
int i;
+ chip->ptp_caps.rx_filters = ptp_ops->rx_filters;
+
/* Disable timestamping on all ports. */
- for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
+ for (i = 0; i < n_ports; ++i) {
err = mv88e6xxx_hwtstamp_port_setup(chip, i);
if (err)
return err;
@@ -611,6 +739,30 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
return 0;
}
+int mv88e6xxx_hwtstamp_setup_unlocked(struct mv88e6xxx_chip *chip)
+{
+ unsigned int n_ports = mv88e6xxx_num_ports(chip);
+ int i, err;
+
+ for (i = err = 0; i < n_ports; ++i) {
+ err = marvell_ts_probe(&chip->ptp_ts[i], chip->dev, chip->tai,
+ &chip->ptp_caps, &mv88e6xxx_ts_ops, i);
+ if (err)
+ break;
+ }
+
+ if (err)
+ while (i--)
+ marvell_ts_remove(&chip->ptp_ts[i]);
+
+ return err;
+}
+
void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip)
{
+ unsigned int n_ports = mv88e6xxx_num_ports(chip);
+ int i;
+
+ for (i = 0; i < n_ports; i++)
+ marvell_ts_remove(&chip->ptp_ts[i]);
}
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index 747351d59921..f82383764653 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -125,6 +125,7 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct kernel_ethtool_ts_info *info);
long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip);
+int mv88e6xxx_hwtstamp_setup_unlocked(struct mv88e6xxx_chip *chip);
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip);
int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port);
@@ -172,6 +173,11 @@ static inline int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
return 0;
}
+static inline int mv88e6xxx_hwtstamp_setup_unlocked(struct mv88e6xxx_chip *chip)
+{
+ return 0;
+}
+
static inline void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip)
{
}
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 17/20] net: dsa: mv88e6xxx: switch tx timestamping to core
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (15 preceding siblings ...)
2025-09-18 17:40 ` [PATCH RFC net-next 16/20] net: dsa: mv88e6xxx: add beginnings of generic Marvell PTP ts layer Russell King (Oracle)
@ 2025-09-18 17:40 ` Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 18/20] net: dsa: mv88e6xxx: switch rx " Russell King (Oracle)
` (2 subsequent siblings)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:40 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
---
drivers/net/dsa/mv88e6xxx/chip.h | 6 --
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 116 ++-------------------------
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 3 -
3 files changed, 7 insertions(+), 118 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index a297b8867225..16de29c6cd43 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -222,7 +222,6 @@ struct mv88e6xxx_irq {
/* state flags for mv88e6xxx_port_hwtstamp::state */
enum {
MV88E6XXX_HWTSTAMP_ENABLED,
- MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
};
struct mv88e6xxx_port_hwtstamp {
@@ -236,11 +235,6 @@ struct mv88e6xxx_port_hwtstamp {
struct sk_buff_head rx_queue;
struct sk_buff_head rx_queue2;
- /* Resources for transmit timestamping */
- unsigned long tx_tstamp_start;
- struct sk_buff *tx_skb;
- u16 tx_seq_id;
-
/* Current timestamp configuration */
struct kernel_hwtstamp_config tstamp_config;
};
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 3e6a0481fc19..7422beba5496 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -357,90 +357,6 @@ bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
return true;
}
-static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
- struct mv88e6xxx_port_hwtstamp *ps)
-{
- const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
- struct skb_shared_hwtstamps shhwtstamps;
- u16 departure_block[4], status;
- struct sk_buff *tmp_skb;
- u32 time_raw;
- int err;
- u64 ns;
-
- if (!ps->tx_skb)
- return 0;
-
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
- ptp_ops->dep_sts_reg,
- departure_block,
- ARRAY_SIZE(departure_block));
- mv88e6xxx_reg_unlock(chip);
-
- if (err)
- goto free_and_clear_skb;
-
- if (!(departure_block[0] & MV88E6XXX_PTP_TS_VALID)) {
- if (time_is_before_jiffies(ps->tx_tstamp_start +
- TX_TSTAMP_TIMEOUT)) {
- dev_warn(chip->dev, "p%d: clearing tx timestamp hang\n",
- ps->port_id);
- goto free_and_clear_skb;
- }
- /* The timestamp should be available quickly, while getting it
- * is high priority and time bounded to only 10ms. A poll is
- * warranted so restart the work.
- */
- return 1;
- }
-
- /* We have the timestamp; go ahead and clear valid now */
- mv88e6xxx_reg_lock(chip);
- mv88e6xxx_port_ptp_write(chip, ps->port_id, ptp_ops->dep_sts_reg, 0);
- mv88e6xxx_reg_unlock(chip);
-
- status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK;
- if (status != MV88E6XXX_PTP_TS_STATUS_NORMAL) {
- dev_warn(chip->dev, "p%d: tx timestamp overrun\n", ps->port_id);
- goto free_and_clear_skb;
- }
-
- if (departure_block[3] != ps->tx_seq_id) {
- dev_warn(chip->dev, "p%d: unexpected seq. id\n", ps->port_id);
- goto free_and_clear_skb;
- }
-
- memset(&shhwtstamps, 0, sizeof(shhwtstamps));
- time_raw = ((u32)departure_block[2] << 16) | departure_block[1];
- ns = marvell_tai_cyc2time(chip->tai, time_raw);
- shhwtstamps.hwtstamp = ns_to_ktime(ns);
-
- dev_dbg(chip->dev,
- "p%d: txtstamp %llx status 0x%04x skb ID 0x%04x hw ID 0x%04x\n",
- ps->port_id, ktime_to_ns(shhwtstamps.hwtstamp),
- departure_block[0], ps->tx_seq_id, departure_block[3]);
-
- /* skb_complete_tx_timestamp() will free up the client to make
- * another timestamp-able transmit. We have to be ready for it
- * -- by clearing the ps->tx_skb "flag" -- beforehand.
- */
-
- tmp_skb = ps->tx_skb;
- ps->tx_skb = NULL;
- clear_bit_unlock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
- skb_complete_tx_timestamp(tmp_skb, &shhwtstamps);
-
- return 0;
-
-free_and_clear_skb:
- dev_kfree_skb_any(ps->tx_skb);
- ps->tx_skb = NULL;
- clear_bit_unlock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
-
- return 0;
-}
-
long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip)
{
struct dsa_switch *ds = chip->ds;
@@ -453,16 +369,7 @@ long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip)
continue;
ps = &chip->port_hwtstamp[i];
- if (test_bit(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state) &&
- mv88e6xxx_txtstamp_work(chip, ps))
- delay = 1;
-
mv88e6xxx_rxtstamp_work(chip, ps);
- }
-
- for (i = 0; i < ds->num_ports; i++) {
- if (!dsa_is_user_port(ds, i))
- continue;
ret = marvell_ts_aux_work(&chip->ptp_ts[i]);
if (ret >= 0 && (delay == -1 || delay > ret))
@@ -476,34 +383,25 @@ void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb)
{
struct mv88e6xxx_chip *chip = ds->priv;
- struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
- struct ptp_header *hdr;
struct sk_buff *clone;
unsigned int type;
- type = ptp_classify_raw(skb);
- if (type == PTP_CLASS_NONE)
+ /* The DSA core will have checked the tx_flags of the skb, so we only
+ * see packets that have had hardware timestamping requested here.
+ */
+ if (!chip->info->ptp_support)
return;
- hdr = mv88e6xxx_should_tstamp(chip, port, skb, type);
- if (!hdr)
+ type = ptp_classify_raw(skb);
+ if (type == PTP_CLASS_NONE)
return;
clone = skb_clone_sk(skb);
if (!clone)
return;
- if (test_and_set_bit_lock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
- &ps->state)) {
+ if (!marvell_ts_txtstamp(&chip->ptp_ts[port], clone, type))
kfree_skb(clone);
- return;
- }
-
- ps->tx_skb = clone;
- ps->tx_tstamp_start = jiffies;
- ps->tx_seq_id = be16_to_cpu(hdr->sequence_id);
-
- marvell_tai_schedule(chip->tai, 0);
}
int mv88e6165_global_disable(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index f82383764653..f27fe0cb27ea 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -103,9 +103,6 @@
/* Status fields for arrival and depature timestamp status registers */
#define MV88E6XXX_PTP_TS_STATUS_MASK 0x0006
-#define MV88E6XXX_PTP_TS_STATUS_NORMAL 0x0000
-#define MV88E6XXX_PTP_TS_STATUS_OVERWITTEN 0x0002
-#define MV88E6XXX_PTP_TS_STATUS_DISCARDED 0x0004
#define MV88E6XXX_PTP_TS_VALID 0x0001
#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 18/20] net: dsa: mv88e6xxx: switch rx timestamping to core
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (16 preceding siblings ...)
2025-09-18 17:40 ` [PATCH RFC net-next 17/20] net: dsa: mv88e6xxx: switch tx timestamping to core Russell King (Oracle)
@ 2025-09-18 17:40 ` Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 19/20] net: dsa: mv88e6xxx: switch hwtstamp config to core XXX Fix 6165 Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 20/20] net: dsa: mv88e6xxx: add ptp irq support Russell King (Oracle)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:40 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.h | 7 --
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 154 +--------------------------
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 4 -
3 files changed, 2 insertions(+), 163 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 16de29c6cd43..0c41b5595dd3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -225,16 +225,9 @@ enum {
};
struct mv88e6xxx_port_hwtstamp {
- /* Port index */
- int port_id;
-
/* Timestamping state */
unsigned long state;
- /* Resources for receive timestamping */
- struct sk_buff_head rx_queue;
- struct sk_buff_head rx_queue2;
-
/* Current timestamp configuration */
struct kernel_hwtstamp_config tstamp_config;
};
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 7422beba5496..fd4afb5e4d49 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -209,158 +209,17 @@ int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
return 0;
}
-/* Returns a pointer to the PTP header if the caller should time stamp,
- * or NULL if the caller should not.
- */
-static struct ptp_header *mv88e6xxx_should_tstamp(struct mv88e6xxx_chip *chip,
- int port, struct sk_buff *skb,
- unsigned int type)
-{
- struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
- struct ptp_header *hdr;
-
- if (!chip->info->ptp_support)
- return NULL;
-
- hdr = ptp_parse_header(skb, type);
- if (!hdr)
- return NULL;
-
- if (!test_bit(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state))
- return NULL;
-
- return hdr;
-}
-
-static int mv88e6xxx_ts_valid(u16 status)
-{
- if (!(status & MV88E6XXX_PTP_TS_VALID))
- return 0;
- if (status & MV88E6XXX_PTP_TS_STATUS_MASK)
- return 0;
- return 1;
-}
-
-static int seq_match(struct sk_buff *skb, u16 ts_seqid)
-{
- unsigned int type = SKB_PTP_TYPE(skb);
- struct ptp_header *hdr;
-
- hdr = ptp_parse_header(skb, type);
-
- return ts_seqid == ntohs(hdr->sequence_id);
-}
-
-static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
- struct mv88e6xxx_port_hwtstamp *ps,
- struct sk_buff *skb, u16 reg,
- struct sk_buff_head *rxq)
-{
- u16 buf[4] = { 0 }, status, seq_id;
- struct skb_shared_hwtstamps *shwt;
- struct sk_buff_head received;
- u64 ns, timelo, timehi;
- unsigned long flags;
- int err;
-
- /* The latched timestamp belongs to one of the received frames. */
- __skb_queue_head_init(&received);
- spin_lock_irqsave(&rxq->lock, flags);
- skb_queue_splice_tail_init(rxq, &received);
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
- reg, buf, ARRAY_SIZE(buf));
- mv88e6xxx_reg_unlock(chip);
- if (err)
- pr_err("failed to get the receive time stamp\n");
-
- status = buf[0];
- timelo = buf[1];
- timehi = buf[2];
- seq_id = buf[3];
-
- if (status & MV88E6XXX_PTP_TS_VALID) {
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_port_ptp_write(chip, ps->port_id, reg, 0);
- mv88e6xxx_reg_unlock(chip);
- if (err)
- pr_err("failed to clear the receive status\n");
- }
- /* Since the device can only handle one time stamp at a time,
- * we purge any extra frames from the queue.
- */
- for ( ; skb; skb = __skb_dequeue(&received)) {
- if (mv88e6xxx_ts_valid(status) && seq_match(skb, seq_id)) {
- ns = timehi << 16 | timelo;
-
- ns = marvell_tai_cyc2time(chip->tai, ns);
- shwt = skb_hwtstamps(skb);
- memset(shwt, 0, sizeof(*shwt));
- shwt->hwtstamp = ns_to_ktime(ns);
- status &= ~MV88E6XXX_PTP_TS_VALID;
- }
- netif_rx(skb);
- }
-}
-
-static void mv88e6xxx_rxtstamp_work(struct mv88e6xxx_chip *chip,
- struct mv88e6xxx_port_hwtstamp *ps)
-{
- const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
- struct sk_buff *skb;
-
- skb = skb_dequeue(&ps->rx_queue);
-
- if (skb)
- mv88e6xxx_get_rxts(chip, ps, skb, ptp_ops->arr0_sts_reg,
- &ps->rx_queue);
-
- skb = skb_dequeue(&ps->rx_queue2);
- if (skb)
- mv88e6xxx_get_rxts(chip, ps, skb, ptp_ops->arr1_sts_reg,
- &ps->rx_queue2);
-}
-
-static int is_pdelay_resp(const struct ptp_header *hdr)
-{
- return (hdr->tsmt & 0xf) == 3;
-}
-
bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type)
{
- struct mv88e6xxx_port_hwtstamp *ps;
- struct mv88e6xxx_chip *chip;
- struct ptp_header *hdr;
-
- chip = ds->priv;
- ps = &chip->port_hwtstamp[port];
-
- if (ps->tstamp_config.rx_filter != HWTSTAMP_FILTER_PTP_V2_EVENT)
- return false;
-
- hdr = mv88e6xxx_should_tstamp(chip, port, skb, type);
- if (!hdr)
- return false;
-
- SKB_PTP_TYPE(skb) = type;
-
- if (is_pdelay_resp(hdr))
- skb_queue_tail(&ps->rx_queue2, skb);
- else
- skb_queue_tail(&ps->rx_queue, skb);
-
- marvell_tai_schedule(chip->tai, 0);
+ struct mv88e6xxx_chip *chip = ds->priv;
- return true;
+ return marvell_ts_rxtstamp(&chip->ptp_ts[port], skb, type);
}
long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip)
{
struct dsa_switch *ds = chip->ds;
- struct mv88e6xxx_port_hwtstamp *ps;
long ret, delay = -1;
int i;
@@ -368,9 +227,6 @@ long mv88e6xxx_hwtstamp_work(struct mv88e6xxx_chip *chip)
if (!dsa_is_user_port(ds, i))
continue;
- ps = &chip->port_hwtstamp[i];
- mv88e6xxx_rxtstamp_work(chip, ps);
-
ret = marvell_ts_aux_work(&chip->ptp_ts[i]);
if (ret >= 0 && (delay == -1 || delay > ret))
delay = ret;
@@ -446,12 +302,6 @@ int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port)
static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
{
const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
- struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
-
- ps->port_id = port;
-
- skb_queue_head_init(&ps->rx_queue);
- skb_queue_head_init(&ps->rx_queue2);
if (ptp_ops->port_disable)
return ptp_ops->port_disable(chip, port);
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index f27fe0cb27ea..f6182658c971 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -101,10 +101,6 @@
/* Offset 0x13: PTP Departure Sequence ID */
#define MV88E6XXX_PORT_PTP_DEP_SEQID 0x13
-/* Status fields for arrival and depature timestamp status registers */
-#define MV88E6XXX_PTP_TS_STATUS_MASK 0x0006
-#define MV88E6XXX_PTP_TS_VALID 0x0001
-
#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 19/20] net: dsa: mv88e6xxx: switch hwtstamp config to core XXX Fix 6165
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (17 preceding siblings ...)
2025-09-18 17:40 ` [PATCH RFC net-next 18/20] net: dsa: mv88e6xxx: switch rx " Russell King (Oracle)
@ 2025-09-18 17:40 ` Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 20/20] net: dsa: mv88e6xxx: add ptp irq support Russell King (Oracle)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:40 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
---
drivers/net/dsa/mv88e6xxx/chip.h | 16 +--
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 151 +++++++--------------------
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 11 --
3 files changed, 36 insertions(+), 142 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 0c41b5595dd3..db95265efa02 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -219,19 +219,6 @@ struct mv88e6xxx_irq {
int nirqs;
};
-/* state flags for mv88e6xxx_port_hwtstamp::state */
-enum {
- MV88E6XXX_HWTSTAMP_ENABLED,
-};
-
-struct mv88e6xxx_port_hwtstamp {
- /* Timestamping state */
- unsigned long state;
-
- /* Current timestamp configuration */
- struct kernel_hwtstamp_config tstamp_config;
-};
-
enum mv88e6xxx_policy_mapping {
MV88E6XXX_POLICY_MAPPING_DA,
MV88E6XXX_POLICY_MAPPING_SA,
@@ -403,16 +390,15 @@ struct mv88e6xxx_chip {
struct marvell_tai *tai;
struct ptp_pin_desc pin_config[MV88E6XXX_MAX_GPIO];
- u16 enable_count;
/* Current ingress and egress monitor ports */
int egress_dest_port;
int ingress_dest_port;
/* Per-port timestamping resources. */
- struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
struct marvell_ts ptp_ts[DSA_MAX_PORTS];
struct marvell_ts_caps ptp_caps;
+ u16 ptp_ts_enable_count;
/* Array of port structures. */
struct mv88e6xxx_port ports[DSA_MAX_PORTS];
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index fd4afb5e4d49..4f6b2706a8be 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -82,9 +82,7 @@ static int mv88e6xxx_ptp_read(struct mv88e6xxx_chip *chip, int addr,
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct kernel_ethtool_ts_info *info)
{
- struct mv88e6xxx_chip *chip;
-
- chip = ds->priv;
+ struct mv88e6xxx_chip *chip = ds->priv;
if (!chip->info->ptp_support)
return -EOPNOTSUPP;
@@ -94,119 +92,24 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
return 0;
}
-static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
- struct kernel_hwtstamp_config *config)
-{
- const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
- struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
- bool tstamp_enable = false;
-
- /* Prevent the TX/RX paths from trying to interact with the
- * timestamp hardware while we reconfigure it.
- */
- clear_bit_unlock(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state);
-
- switch (config->tx_type) {
- case HWTSTAMP_TX_OFF:
- tstamp_enable = false;
- break;
- case HWTSTAMP_TX_ON:
- tstamp_enable = true;
- break;
- default:
- return -ERANGE;
- }
-
- /* The switch supports timestamping both L2 and L4; one cannot be
- * disabled independently of the other.
- */
-
- if (!(BIT(config->rx_filter) & ptp_ops->rx_filters)) {
- config->rx_filter = HWTSTAMP_FILTER_NONE;
- dev_dbg(chip->dev, "Unsupported rx_filter %d\n",
- config->rx_filter);
- return -ERANGE;
- }
-
- switch (config->rx_filter) {
- case HWTSTAMP_FILTER_NONE:
- tstamp_enable = false;
- break;
- case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
- case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
- case HWTSTAMP_FILTER_PTP_V2_EVENT:
- case HWTSTAMP_FILTER_PTP_V2_SYNC:
- case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
- break;
- case HWTSTAMP_FILTER_ALL:
- default:
- config->rx_filter = HWTSTAMP_FILTER_NONE;
- return -ERANGE;
- }
-
- mv88e6xxx_reg_lock(chip);
- if (tstamp_enable) {
- chip->enable_count += 1;
- if (chip->enable_count == 1 && ptp_ops->global_enable)
- ptp_ops->global_enable(chip);
- if (ptp_ops->port_enable)
- ptp_ops->port_enable(chip, port);
- } else {
- if (ptp_ops->port_disable)
- ptp_ops->port_disable(chip, port);
- chip->enable_count -= 1;
- if (chip->enable_count == 0 && ptp_ops->global_disable)
- ptp_ops->global_disable(chip);
- }
- mv88e6xxx_reg_unlock(chip);
-
- /* Once hardware has been configured, enable timestamp checks
- * in the RX/TX paths.
- */
- if (tstamp_enable)
- set_bit(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state);
-
- return 0;
-}
-
int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct mv88e6xxx_chip *chip = ds->priv;
- struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
- int err;
if (!chip->info->ptp_support)
return -EOPNOTSUPP;
- err = mv88e6xxx_set_hwtstamp_config(chip, port, config);
- if (err)
- return err;
-
- /* Save the chosen configuration to be returned later. */
- ps->tstamp_config = *config;
-
- return 0;
+ return marvell_ts_hwtstamp_set(&chip->ptp_ts[port], config, extack);
}
int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config)
{
struct mv88e6xxx_chip *chip = ds->priv;
- struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
-
- if (!chip->info->ptp_support)
- return -EOPNOTSUPP;
- *config = ps->tstamp_config;
-
- return 0;
+ return marvell_ts_hwtstamp_get(&chip->ptp_ts[port], config);
}
bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
@@ -316,6 +219,36 @@ static int mv88e6xxx_ts_global_write(struct device *dev, u8 reg, u16 val)
return chip->info->ops->avb_ops->ptp_write(chip, reg, val);
}
+static int mv88e6xxx_ts_port_enable(struct device *dev, u8 port)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ const struct mv88e6xxx_ptp_ops *ptp_ops;
+
+ ptp_ops = chip->info->ops->ptp_ops;
+ if (ptp_ops->global_enable) {
+ mv88e6xxx_reg_lock(chip);
+ if (!chip->ptp_ts_enable_count++)
+ ptp_ops->global_enable(chip);
+ mv88e6xxx_reg_unlock(chip);
+ }
+
+ return 0;
+}
+
+static void mv88e6xxx_ts_port_disable(struct device *dev, u8 port)
+{
+ struct mv88e6xxx_chip *chip = dev_to_chip(dev);
+ const struct mv88e6xxx_ptp_ops *ptp_ops;
+
+ ptp_ops = chip->info->ops->ptp_ops;
+ if (ptp_ops->global_disable) {
+ mv88e6xxx_reg_lock(chip);
+ if (!--chip->ptp_ts_enable_count)
+ ptp_ops->global_disable(chip);
+ mv88e6xxx_reg_unlock(chip);
+ }
+}
+
/* The device differences are:
* ts_reg MV88E6165 Others
* TS_ARR0 MV88E6165_PORT_PTP_ARR0_STS MV88E6XXX_PORT_PTP_ARR0_STS
@@ -423,6 +356,8 @@ static int mv88e6xxx_ts_port_modify(struct device *dev, u8 port, u8 reg,
static const struct marvell_ts_ops mv88e6xxx_ts_ops = {
.ts_global_write = mv88e6xxx_ts_global_write,
+ .ts_port_enable = mv88e6xxx_ts_port_enable,
+ .ts_port_disable = mv88e6xxx_ts_port_disable,
.ts_port_read_ts = mv88e6xxx_ts_port_read_ts,
.ts_port_write = mv88e6xxx_ts_port_write,
.ts_port_modify = mv88e6xxx_ts_port_modify,
@@ -455,22 +390,6 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
if (err)
return err;
- /* MV88E6XXX_PTP_MSG_TYPE is a mask of PTP message types to
- * timestamp. This affects all ports that have timestamping enabled,
- * but the timestamp config is per-port; thus we configure all events
- * here and only support the HWTSTAMP_FILTER_*_EVENT filter types.
- */
- err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_MSGTYPE,
- MV88E6XXX_PTP_MSGTYPE_ALL_EVENT);
- if (err)
- return err;
-
- /* Use ARRIVAL1 for peer delay response messages. */
- err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_TS_ARRIVAL_PTR,
- MV88E6XXX_PTP_MSGTYPE_PDLAY_RES);
- if (err)
- return err;
-
/* 88E6341 devices default to timestamping at the PHY, but this has
* a hardware issue that results in unreliable timestamps. Force
* these devices to timestamp at the MAC.
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index f6182658c971..caeee3b1256d 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -19,17 +19,6 @@
/* Offset 0x00: PTP EtherType */
#define MV88E6XXX_PTP_ETHERTYPE 0x00
-/* Offset 0x01: Message Type Timestamp Enables */
-#define MV88E6XXX_PTP_MSGTYPE 0x01
-#define MV88E6XXX_PTP_MSGTYPE_SYNC 0x0001
-#define MV88E6XXX_PTP_MSGTYPE_DELAY_REQ 0x0002
-#define MV88E6XXX_PTP_MSGTYPE_PDLAY_REQ 0x0004
-#define MV88E6XXX_PTP_MSGTYPE_PDLAY_RES 0x0008
-#define MV88E6XXX_PTP_MSGTYPE_ALL_EVENT 0x000f
-
-/* Offset 0x02: Timestamp Arrival Capture Pointers */
-#define MV88E6XXX_PTP_TS_ARRIVAL_PTR 0x02
-
/* Offset 0x05: PTP Global Configuration */
#define MV88E6165_PTP_CFG 0x05
#define MV88E6165_PTP_CFG_TSPEC_MASK 0xf000
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH RFC net-next 20/20] net: dsa: mv88e6xxx: add ptp irq support
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
` (18 preceding siblings ...)
2025-09-18 17:40 ` [PATCH RFC net-next 19/20] net: dsa: mv88e6xxx: switch hwtstamp config to core XXX Fix 6165 Russell King (Oracle)
@ 2025-09-18 17:40 ` Russell King (Oracle)
19 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 17:40 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/chip.h | 2 +
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 60 +++++++++++++++++++++++++++-
2 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index db95265efa02..361c21aaf64b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -399,6 +399,8 @@ struct mv88e6xxx_chip {
struct marvell_ts ptp_ts[DSA_MAX_PORTS];
struct marvell_ts_caps ptp_caps;
u16 ptp_ts_enable_count;
+ int avb_irq;
+ char avb_irq_name[64];
/* Array of port structures. */
struct mv88e6xxx_port ports[DSA_MAX_PORTS];
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 4f6b2706a8be..d8c675886ea5 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -11,9 +11,12 @@
*/
#include "chip.h"
+#include "global1.h"
#include "global2.h"
#include "hwtstamp.h"
#include "ptp.h"
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/ptp_classify.h>
#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
@@ -163,6 +166,34 @@ void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
kfree_skb(clone);
}
+static irqreturn_t mv88e6xxx_ptp_irq_thread_fn(int irq, void *dev_id)
+{
+ struct mv88e6xxx_chip *chip = dev_id;
+ irqreturn_t r, ret = IRQ_NONE;
+ unsigned int n, max;
+ unsigned long mask;
+ u16 status;
+ int err;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_ptp_read(chip, MV88E6XXX_PTP_IRQ_STATUS, &status);
+ mv88e6xxx_reg_unlock(chip);
+ if (err || !status)
+ return IRQ_NONE;
+
+ dev_printk(KERN_DEBUG, chip->dev, "ptp irq, status=%04x\n", status);
+
+ mask = status;
+ max = chip->ds->num_ports;
+ for_each_set_bit(n, &mask, max) {
+ r = marvell_ts_irq(&chip->ptp_ts[n]);
+ if (r != IRQ_NONE)
+ ret = r;
+ }
+
+ return ret;
+}
+
int mv88e6165_global_disable(struct mv88e6xxx_chip *chip)
{
u16 val;
@@ -409,7 +440,21 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
int mv88e6xxx_hwtstamp_setup_unlocked(struct mv88e6xxx_chip *chip)
{
unsigned int n_ports = mv88e6xxx_num_ports(chip);
- int i, err;
+ int irq, i, err;
+
+ irq = irq_find_mapping(chip->g1_irq.domain, MV88E6XXX_G1_STS_IRQ_AVB);
+ if (irq > 0) {
+ chip->avb_irq = irq;
+ snprintf(chip->avb_irq_name, sizeof(chip->avb_irq_name),
+ "mv88e6xxx-%s-g1-avb", dev_name(chip->dev));
+
+ if (request_threaded_irq(irq, NULL, mv88e6xxx_ptp_irq_thread_fn,
+ IRQF_ONESHOT, chip->avb_irq_name,
+ chip)) {
+ irq_dispose_mapping(irq);
+ chip->avb_irq = 0;
+ }
+ }
for (i = err = 0; i < n_ports; ++i) {
err = marvell_ts_probe(&chip->ptp_ts[i], chip->dev, chip->tai,
@@ -418,10 +463,16 @@ int mv88e6xxx_hwtstamp_setup_unlocked(struct mv88e6xxx_chip *chip)
break;
}
- if (err)
+ if (err) {
while (i--)
marvell_ts_remove(&chip->ptp_ts[i]);
+ if (chip->avb_irq) {
+ irq_dispose_mapping(chip->avb_irq);
+ chip->avb_irq = 0;
+ }
+ }
+
return err;
}
@@ -432,4 +483,9 @@ void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip)
for (i = 0; i < n_ports; i++)
marvell_ts_remove(&chip->ptp_ts[i]);
+
+ if (chip->avb_irq) {
+ free_irq(chip->avb_irq, chip);
+ irq_dispose_mapping(chip->avb_irq);
+ }
}
--
2.47.3
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support
2025-09-18 17:39 ` [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support Russell King
@ 2025-09-18 20:12 ` Andrew Lunn
2025-09-18 20:33 ` Russell King (Oracle)
0 siblings, 1 reply; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:12 UTC (permalink / raw)
To: Russell King
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
> +static u64 marvell_phy_tai_clock_read(struct device *dev,
> + struct ptp_system_timestamp *sts)
> +{
> + struct phy_device *phydev = to_phy_device(dev);
> + int err, oldpage, lo, hi;
> +
> + oldpage = phy_select_page(phydev, MARVELL_PAGE_PTP_GLOBAL);
> + if (oldpage >= 0) {
> + /* 88e151x says to write 0x8e0e */
> + ptp_read_system_prets(sts);
> + err = __phy_write(phydev, PTPG_READPLUS_COMMAND, 0x8e0e);
> + ptp_read_system_postts(sts);
> + lo = __phy_read(phydev, PTPG_READPLUS_DATA);
> + hi = __phy_read(phydev, PTPG_READPLUS_DATA);
> + }
> + err = phy_restore_page(phydev, oldpage, err);
> +
> + if (err || lo < 0 || hi < 0)
> + return 0;
> +
> + return lo | hi << 16;
What happens when hi is >= 0x8000? Doesn't that result in undefined
behaviour for 32 bit machines? The u64 result we are trying to return
is big enough to hold the value. Does the hi need promoting to u64
before doing the shift?
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 05/20] net: dsa: mv88e6xxx: convert PTP clock_read() method to take chip
2025-09-18 17:39 ` [PATCH RFC net-next 05/20] net: dsa: mv88e6xxx: convert PTP clock_read() method to take chip Russell King (Oracle)
@ 2025-09-18 20:13 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:13 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 06:39:17PM +0100, Russell King (Oracle) wrote:
> The various clock_read() method implementations do not make use of the
> passed struct cycle_counter except to convert to the parent struct
> mv88e6xxx_chip. The caller of these methods has already done this.
>
> Pass a pointer to struct mv88e6xxx_chip instead.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 09/20] net: dsa: mv88e6xxx: always verify PTP_PF_NONE
2025-09-18 17:39 ` [PATCH RFC net-next 09/20] net: dsa: mv88e6xxx: always verify PTP_PF_NONE Russell King (Oracle)
@ 2025-09-18 20:14 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:14 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 06:39:37PM +0100, Russell King (Oracle) wrote:
> Setting a pin to "no function" should always be supported. Move this
> to mv88e6xxx_ptp_verify(). This allows mv88e6352_ptp_verify() to be
> simplified as the only supported PTP pin mode function is
> PTP_PF_EXTTS.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support
2025-09-18 20:12 ` Andrew Lunn
@ 2025-09-18 20:33 ` Russell King (Oracle)
2025-09-19 1:47 ` Andrew Lunn
0 siblings, 1 reply; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-18 20:33 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 10:12:02PM +0200, Andrew Lunn wrote:
> > +static u64 marvell_phy_tai_clock_read(struct device *dev,
> > + struct ptp_system_timestamp *sts)
> > +{
> > + struct phy_device *phydev = to_phy_device(dev);
> > + int err, oldpage, lo, hi;
> > +
> > + oldpage = phy_select_page(phydev, MARVELL_PAGE_PTP_GLOBAL);
> > + if (oldpage >= 0) {
> > + /* 88e151x says to write 0x8e0e */
> > + ptp_read_system_prets(sts);
> > + err = __phy_write(phydev, PTPG_READPLUS_COMMAND, 0x8e0e);
> > + ptp_read_system_postts(sts);
> > + lo = __phy_read(phydev, PTPG_READPLUS_DATA);
> > + hi = __phy_read(phydev, PTPG_READPLUS_DATA);
> > + }
> > + err = phy_restore_page(phydev, oldpage, err);
> > +
> > + if (err || lo < 0 || hi < 0)
> > + return 0;
> > +
> > + return lo | hi << 16;
>
> What happens when hi is >= 0x8000? Doesn't that result in undefined
> behaviour for 32 bit machines? The u64 result we are trying to return
> is big enough to hold the value. Does the hi need promoting to u64
> before doing the shift?
Good point - looking at the generated code, it gets sign-extended
to a 64 bit value. So, hi=0x8000 results in 0xffffffff8000XXXX
being returned.
Does it matter? There are two functions that call the cyclecounter
->read() method. timecounter_init() sets ->cycle_last from the
value, and timecounter_read_delta() does this:
cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
before updating ->cycle_last with the returned value. As the
mask is initialised thusly:
tai->cyclecounter.mask = CYCLECOUNTER_MASK(32);
this masks off the sign-extended high 32-bits, giving us back
a value of 0x8000XXXX.
So, while the sign extension is undesirable, it has no effect on
the operation. Is it worth throwing casts in the code? I suspect
that's a matter of personal opinion.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 02/20] net: phy: add hwtstamp_get() method for mii timestampers
2025-09-18 17:39 ` [PATCH RFC net-next 02/20] net: phy: add hwtstamp_get() method for mii timestampers Russell King (Oracle)
@ 2025-09-18 20:38 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:38 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 06:39:02PM +0100, Russell King (Oracle) wrote:
> Add the missing hwtstamp_get() method for mii timestampers so PHYs can
> report their configuration back to userspace.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 04/20] net: dsa: mv88e6xxx: split out set_ptp_cpu_port() code
2025-09-18 17:39 ` [PATCH RFC net-next 04/20] net: dsa: mv88e6xxx: split out set_ptp_cpu_port() code Russell King (Oracle)
@ 2025-09-18 20:46 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:46 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 06:39:12PM +0100, Russell King (Oracle) wrote:
> Split out the code which sets up the upstream CPU port for PTP. This
> will be required when converted to the generic Marvell PTP library.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
> ---
> drivers/net/dsa/mv88e6xxx/ptp.c | 42 ++++++++++++++++++++-------------
> 1 file changed, 25 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
> index f7603573d3a9..b60e4f02c256 100644
> --- a/drivers/net/dsa/mv88e6xxx/ptp.c
> +++ b/drivers/net/dsa/mv88e6xxx/ptp.c
> @@ -444,6 +444,27 @@ const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = {
> (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
> };
>
> +static int mv88e6xxx_set_ptp_cpu_port(struct mv88e6xxx_chip *chip)
> +{
> + struct dsa_port *dp;
> + int upstream = 0;
> + int err;
> +
> + if (!chip->info->ops->ptp_ops->set_ptp_cpu_port)
> + return 0;
> +
> + dsa_switch_for_each_user_port(dp, chip->ds) {
> + upstream = dsa_upstream_port(chip->ds, dp->index);
> + break;
> + }
I think you can use dsa_switch_upstream_port(chip->ds);
It will look less odd than this loop construct.
> - if (ptp_ops->set_ptp_cpu_port) {
> - struct dsa_port *dp;
> - int upstream = 0;
> - int err;
> -
> - dsa_switch_for_each_user_port(dp, chip->ds) {
> - upstream = dsa_upstream_port(chip->ds, dp->index);
> - break;
> - }
Although i see you copied it from here. So keep it if you want.
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 06/20] net: dsa: mv88e6xxx: convert PTP ptp_verify() method to take chip
2025-09-18 17:39 ` [PATCH RFC net-next 06/20] net: dsa: mv88e6xxx: convert PTP ptp_verify() " Russell King (Oracle)
@ 2025-09-18 20:48 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:48 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 06:39:22PM +0100, Russell King (Oracle) wrote:
> Wrap the ptp_ops->ptp_verify() method and convert it to take
> struct mv88e6xxx_chip. This eases the transition to generic Marvell
> PTP.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 07/20] net: dsa: mv88e6xxx: convert PTP ptp_enable() method to take chip
2025-09-18 17:39 ` [PATCH RFC net-next 07/20] net: dsa: mv88e6xxx: convert PTP ptp_enable() " Russell King (Oracle)
@ 2025-09-18 20:48 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:48 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 06:39:27PM +0100, Russell King (Oracle) wrote:
> Wrap the ptp_ops->ptp_enable() method and convert it to take
> struct mv88e6xxx_chip. This eases the transition to generic Marvell
> PTP.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 08/20] net: dsa: mv88e6xxx: convert mv88e6xxx_hwtstamp_work() to take chip
2025-09-18 17:39 ` [PATCH RFC net-next 08/20] net: dsa: mv88e6xxx: convert mv88e6xxx_hwtstamp_work() " Russell King (Oracle)
@ 2025-09-18 20:51 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:51 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 06:39:32PM +0100, Russell King (Oracle) wrote:
> Instead of passing a pointer to the ptp_clock_info structure, pass a
> pointer to mv88e6xxx_chip instead. This allows the transition to the
> generic marvell PTP library easier.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 11/20] net: dsa: mv88e6xxx: split out EXTTS pin setup
2025-09-18 17:39 ` [PATCH RFC net-next 11/20] net: dsa: mv88e6xxx: split out EXTTS pin setup Russell King (Oracle)
@ 2025-09-18 20:59 ` Andrew Lunn
2025-09-28 9:51 ` Russell King (Oracle)
0 siblings, 1 reply; 35+ messages in thread
From: Andrew Lunn @ 2025-09-18 20:59 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
> static const struct mv88e6xxx_cc_coeffs *
> mv88e6xxx_cc_coeff_get(struct mv88e6xxx_chip *chip)
> {
> @@ -352,27 +366,18 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
> return -EBUSY;
>
> mv88e6xxx_reg_lock(chip);
> + err = mv88e6352_ptp_pin_setup(chip, pin, PTP_PF_EXTTS, on);
>
> - if (on) {
> - func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
> -
> - err = mv88e6352_set_gpio_func(chip, pin, func, true);
> - if (err)
> - goto out;
> -
> + if (!on) {
Inverting the if () makes this a little bit harder to review. But it
does remove a goto. I probably would of kept the code in the same
order. But:
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support
2025-09-18 20:33 ` Russell King (Oracle)
@ 2025-09-19 1:47 ` Andrew Lunn
0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2025-09-19 1:47 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 09:33:27PM +0100, Russell King (Oracle) wrote:
> On Thu, Sep 18, 2025 at 10:12:02PM +0200, Andrew Lunn wrote:
> > > +static u64 marvell_phy_tai_clock_read(struct device *dev,
> > > + struct ptp_system_timestamp *sts)
> > > +{
> > > + struct phy_device *phydev = to_phy_device(dev);
> > > + int err, oldpage, lo, hi;
> > > +
> > > + oldpage = phy_select_page(phydev, MARVELL_PAGE_PTP_GLOBAL);
> > > + if (oldpage >= 0) {
> > > + /* 88e151x says to write 0x8e0e */
> > > + ptp_read_system_prets(sts);
> > > + err = __phy_write(phydev, PTPG_READPLUS_COMMAND, 0x8e0e);
> > > + ptp_read_system_postts(sts);
> > > + lo = __phy_read(phydev, PTPG_READPLUS_DATA);
> > > + hi = __phy_read(phydev, PTPG_READPLUS_DATA);
> > > + }
> > > + err = phy_restore_page(phydev, oldpage, err);
> > > +
> > > + if (err || lo < 0 || hi < 0)
> > > + return 0;
> > > +
> > > + return lo | hi << 16;
> >
> > What happens when hi is >= 0x8000? Doesn't that result in undefined
> > behaviour for 32 bit machines? The u64 result we are trying to return
> > is big enough to hold the value. Does the hi need promoting to u64
> > before doing the shift?
>
> Good point - looking at the generated code, it gets sign-extended
> to a 64 bit value. So, hi=0x8000 results in 0xffffffff8000XXXX
> being returned.
>
> Does it matter? There are two functions that call the cyclecounter
> ->read() method. timecounter_init() sets ->cycle_last from the
> value, and timecounter_read_delta() does this:
>
> cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
>
> before updating ->cycle_last with the returned value. As the
> mask is initialised thusly:
>
> tai->cyclecounter.mask = CYCLECOUNTER_MASK(32);
>
> this masks off the sign-extended high 32-bits, giving us back
> a value of 0x8000XXXX.
>
> So, while the sign extension is undesirable, it has no effect on
> the operation. Is it worth throwing casts in the code? I suspect
> that's a matter of personal opinion.
I doubt the static analysers can do such a detailed analysis. So at
some point we are going to get patches adding a cast. You could maybe
change hi to a signed 64. That would avoid adding a cast, while still
being O.K. to hold a negative error code from __phy_read().
Andrew
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 10/20] net: dsa: mv88e6xxx: only support EXTTS for pins
2025-09-18 17:39 ` [PATCH RFC net-next 10/20] net: dsa: mv88e6xxx: only support EXTTS for pins Russell King (Oracle)
@ 2025-09-19 11:29 ` Vadim Fedorenko
2025-09-19 13:50 ` Russell King (Oracle)
0 siblings, 1 reply; 35+ messages in thread
From: Vadim Fedorenko @ 2025-09-19 11:29 UTC (permalink / raw)
To: Russell King (Oracle), netdev
Cc: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On 18/09/2025 18:39, Russell King (Oracle) wrote:
> The sole implementation for the PTP verify/enable methods only supports
> the EXTTS function. Move these checks into mv88e6xxx_ptp_verify() and
> mv88e6xxx_ptp_enable(), renaming the ptp_enable() method to
> ptp_enable_extts().
It would be great to add .supported_extts_flags as well to allow
PTP_EXTTS_REQUEST2, take a look at changes in:
https://lore.kernel.org/netdev/20250919103928.3ab57aa2@kmaincent-XPS-13-7390/T/#m579d718f36b2368e476eb400e235fe28f0bd03ff
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 10/20] net: dsa: mv88e6xxx: only support EXTTS for pins
2025-09-19 11:29 ` Vadim Fedorenko
@ 2025-09-19 13:50 ` Russell King (Oracle)
0 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-19 13:50 UTC (permalink / raw)
To: Vadim Fedorenko
Cc: netdev, Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Fri, Sep 19, 2025 at 12:29:43PM +0100, Vadim Fedorenko wrote:
> On 18/09/2025 18:39, Russell King (Oracle) wrote:
> > The sole implementation for the PTP verify/enable methods only supports
> > the EXTTS function. Move these checks into mv88e6xxx_ptp_verify() and
> > mv88e6xxx_ptp_enable(), renaming the ptp_enable() method to
> > ptp_enable_extts().
>
> It would be great to add .supported_extts_flags as well to allow
> PTP_EXTTS_REQUEST2, take a look at changes in:
> https://lore.kernel.org/netdev/20250919103928.3ab57aa2@kmaincent-XPS-13-7390/T/#m579d718f36b2368e476eb400e235fe28f0bd03ff
Marvell DSA already supports .supported_extts_flags, and my changes
aim to do nothing to regress anything that was already supported. I
consider any such regression to be a bug when doing projects like
this.
Thanks.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH RFC net-next 11/20] net: dsa: mv88e6xxx: split out EXTTS pin setup
2025-09-18 20:59 ` Andrew Lunn
@ 2025-09-28 9:51 ` Russell King (Oracle)
0 siblings, 0 replies; 35+ messages in thread
From: Russell King (Oracle) @ 2025-09-28 9:51 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Heiner Kallweit, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Vladimir Oltean
On Thu, Sep 18, 2025 at 10:59:07PM +0200, Andrew Lunn wrote:
> > static const struct mv88e6xxx_cc_coeffs *
> > mv88e6xxx_cc_coeff_get(struct mv88e6xxx_chip *chip)
> > {
> > @@ -352,27 +366,18 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
> > return -EBUSY;
> >
> > mv88e6xxx_reg_lock(chip);
> > + err = mv88e6352_ptp_pin_setup(chip, pin, PTP_PF_EXTTS, on);
> >
> > - if (on) {
> > - func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
> > -
> > - err = mv88e6352_set_gpio_func(chip, pin, func, true);
> > - if (err)
> > - goto out;
> > -
> > + if (!on) {
>
> Inverting the if () makes this a little bit harder to review. But it
> does remove a goto. I probably would of kept the code in the same
> order. But:
>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
It's not the goto, but:
if (on && !err) {
schedule_delayed_work(&chip->tai_event_work,
TAI_EVENT_WORK_INTERVAL);
err = mv88e6352_config_eventcap(chip, rising);
} else if (!on) {
/* Always cancel the work, even if an error occurs */
cancel_delayed_work_sync(&chip->tai_event_work);
}
would be the alternative, which is IMHO less readable, and more
error-prone. However, there is an issue that if
mv88e6352_config_eventcap() returns an error, we leave the work
scheduled. So maybe:
if (on && !err) {
schedule_delayed_work(&chip->tai_event_work,
TAI_EVENT_WORK_INTERVAL);
err = mv88e6352_config_eventcap(chip, rising);
}
if (!on || err) {
/* Always cancel the work, even if an error occurs */
cancel_delayed_work_sync(&chip->tai_event_work);
}
which is more difficult to get one's head around.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2025-09-28 9:51 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18 17:38 [PATCH RFC net-next 00/20] Marvell PTP stuffs Russell King (Oracle)
2025-09-18 17:38 ` [PATCH RFC net-next 01/20] ptp: marvell: add core support for Marvell PTP Russell King
2025-09-18 17:39 ` [PATCH RFC net-next 02/20] net: phy: add hwtstamp_get() method for mii timestampers Russell King (Oracle)
2025-09-18 20:38 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 03/20] net: phy: marvell: add PHY PTP support Russell King
2025-09-18 20:12 ` Andrew Lunn
2025-09-18 20:33 ` Russell King (Oracle)
2025-09-19 1:47 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 04/20] net: dsa: mv88e6xxx: split out set_ptp_cpu_port() code Russell King (Oracle)
2025-09-18 20:46 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 05/20] net: dsa: mv88e6xxx: convert PTP clock_read() method to take chip Russell King (Oracle)
2025-09-18 20:13 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 06/20] net: dsa: mv88e6xxx: convert PTP ptp_verify() " Russell King (Oracle)
2025-09-18 20:48 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 07/20] net: dsa: mv88e6xxx: convert PTP ptp_enable() " Russell King (Oracle)
2025-09-18 20:48 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 08/20] net: dsa: mv88e6xxx: convert mv88e6xxx_hwtstamp_work() " Russell King (Oracle)
2025-09-18 20:51 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 09/20] net: dsa: mv88e6xxx: always verify PTP_PF_NONE Russell King (Oracle)
2025-09-18 20:14 ` Andrew Lunn
2025-09-18 17:39 ` [PATCH RFC net-next 10/20] net: dsa: mv88e6xxx: only support EXTTS for pins Russell King (Oracle)
2025-09-19 11:29 ` Vadim Fedorenko
2025-09-19 13:50 ` Russell King (Oracle)
2025-09-18 17:39 ` [PATCH RFC net-next 11/20] net: dsa: mv88e6xxx: split out EXTTS pin setup Russell King (Oracle)
2025-09-18 20:59 ` Andrew Lunn
2025-09-28 9:51 ` Russell King (Oracle)
2025-09-18 17:39 ` [PATCH RFC net-next 12/20] net: dsa: mv88e6xxx: move EXTTS flag validation and pin lookup Russell King (Oracle)
2025-09-18 17:39 ` [PATCH RFC net-next 13/20] net: dsa: mv88e6xxx: convert to marvell TAI Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 14/20] net: dsa: mv88e6xxx: convert mv88e6xxx_cc_coeffs to marvell_tai_param Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 15/20] net: dsa: mv88e6xxx: allow generic core to configure global regs Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 16/20] net: dsa: mv88e6xxx: add beginnings of generic Marvell PTP ts layer Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 17/20] net: dsa: mv88e6xxx: switch tx timestamping to core Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 18/20] net: dsa: mv88e6xxx: switch rx " Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 19/20] net: dsa: mv88e6xxx: switch hwtstamp config to core XXX Fix 6165 Russell King (Oracle)
2025-09-18 17:40 ` [PATCH RFC net-next 20/20] net: dsa: mv88e6xxx: add ptp irq support Russell King (Oracle)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).