netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vladimir Oltean <olteanv@gmail.com>
To: "David S . Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	netdev@vger.kernel.org
Cc: Andrew Lunn <andrew@lunn.ch>,
	Florian Fainelli <f.fainelli@gmail.com>,
	Vivien Didelot <vivien.didelot@gmail.com>,
	Richard Cochran <richardcochran@gmail.com>,
	Claudiu Manoil <claudiu.manoil@nxp.com>,
	Alexandru Marginean <alexandru.marginean@nxp.com>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Xiaoliang Yang <xiaoliang.yang_1@nxp.com>,
	Hongbo Wang <hongbo.wang@nxp.com>, Po Liu <po.liu@nxp.com>,
	Yangbo Lu <yangbo.lu@nxp.com>,
	Maxim Kochetkov <fido_max@inbox.ru>,
	Eldar Gasanov <eldargasanov2@gmail.com>,
	Andrey L <al@b4comtech.com>,
	UNGLinuxDriver@microchip.com
Subject: [PATCH v3 net-next 15/15] net: dsa: tag_ocelot_8021q: add support for PTP timestamping
Date: Mon, 18 Jan 2021 18:17:31 +0200	[thread overview]
Message-ID: <20210118161731.2837700-16-olteanv@gmail.com> (raw)
In-Reply-To: <20210118161731.2837700-1-olteanv@gmail.com>

From: Vladimir Oltean <vladimir.oltean@nxp.com>

On TX, use the result of the ptp_classify_raw() BPF classifier from
dsa_skb_tx_timestamp() to divert some frames over to the MMIO-based
injection registers.

On RX, set up a VCAP IS2 rule that redirects the frames with an
EtherType for 1588 to the CPU port module (for MMIO based extraction)
and, if the "no XTR IRQ" workaround is in place, copies them to the
dsa_8021q CPU port as well (for notification).

There is a conflict between the VCAP IS2 trapping rule and the semantics
of the BPF classifier. Namely, ptp_classify_raw() deems general messages
as non-timestampable, but still, those are trapped to the CPU port
module since they have an EtherType of ETH_P_1588. So, if the "no XTR
IRQ" workaround is in place, we need to run another BPF classifier on
the frames extracted over MMIO, to avoid duplicates being sent to the
stack (once over Ethernet, once over MMIO). It doesn't look like it's
possible to install VCAP IS2 rules based on keys extracted from the 1588
frame headers.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
Changes in v3:
None.

Changes in v2:
Patch is new.

 drivers/net/dsa/ocelot/felix.c           | 12 +++++
 drivers/net/dsa/ocelot/felix_tag_8021q.c | 61 ++++++++++++++++++++++++
 drivers/net/dsa/ocelot/felix_tag_8021q.h |  7 +++
 drivers/net/ethernet/mscc/ocelot.c       |  3 ++
 drivers/net/ethernet/mscc/ocelot.h       |  8 ----
 include/soc/mscc/ocelot.h                |  9 ++++
 net/dsa/tag_ocelot_8021q.c               | 24 ++++++++++
 7 files changed, 116 insertions(+), 8 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 88ceed15e9cf..59757f29bcf8 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -733,6 +733,18 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
 	struct timespec64 ts;
 	u64 tstamp, val;
 
+	/* If the "no XTR IRQ" workaround is in use, tell DSA to defer this skb
+	 * for RX timestamping. Then free it, and poll for its copy through
+	 * MMIO in the CPU port module, and inject that into the stack from
+	 * ocelot_xtr_poll().
+	 * If the "no XTR IRQ" workaround isn't in use, this is a no-op and
+	 * should be eliminated by the compiler as dead code.
+	 */
+	if (felix_check_xtr_pkt(ocelot, type)) {
+		kfree_skb(skb);
+		return true;
+	}
+
 	ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
 	tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
 
diff --git a/drivers/net/dsa/ocelot/felix_tag_8021q.c b/drivers/net/dsa/ocelot/felix_tag_8021q.c
index 84abfd2eb8a7..c7f7d7624bab 100644
--- a/drivers/net/dsa/ocelot/felix_tag_8021q.c
+++ b/drivers/net/dsa/ocelot/felix_tag_8021q.c
@@ -11,9 +11,70 @@
 #include <soc/mscc/ocelot_vcap.h>
 #include <linux/dsa/8021q.h>
 #include <linux/if_bridge.h>
+#include <linux/ptp_classify.h>
 #include "felix.h"
 #include "felix_tag_8021q.h"
 
+bool felix_check_xtr_pkt(struct ocelot *ocelot, unsigned int ptp_type)
+{
+	struct felix *felix = ocelot_to_felix(ocelot);
+	int err, grp = 0;
+
+	if (!felix->info->quirk_no_xtr_irq)
+		return false;
+
+	if (ptp_type == PTP_CLASS_NONE)
+		return false;
+
+	while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) {
+		struct ocelot_frame_info info = {};
+		struct dsa_port *dp;
+		struct sk_buff *skb;
+		unsigned int type;
+
+		err = ocelot_xtr_poll_xfh(ocelot, grp, &info);
+		if (err)
+			break;
+
+		if (WARN_ON(info.port >= ocelot->num_phys_ports))
+			goto out;
+
+		dp = dsa_to_port(felix->ds, info.port);
+
+		err = ocelot_xtr_poll_frame(ocelot, grp, dp->slave,
+					    &info, &skb);
+		if (err)
+			break;
+
+		/* We trap to the CPU port module all PTP frames, but
+		 * felix_rxtstamp() only gets called for event frames.
+		 * So we need to avoid sending duplicate general
+		 * message frames by running a second BPF classifier
+		 * here and dropping those.
+		 */
+		__skb_push(skb, ETH_HLEN);
+
+		type = ptp_classify_raw(skb);
+
+		__skb_pull(skb, ETH_HLEN);
+
+		if (type == PTP_CLASS_NONE) {
+			kfree_skb(skb);
+			continue;
+		}
+
+		netif_rx(skb);
+	}
+
+out:
+	if (err < 0) {
+		ocelot_write(ocelot, QS_XTR_FLUSH, BIT(grp));
+		ocelot_write(ocelot, QS_XTR_FLUSH, 0);
+	}
+
+	return true;
+}
+
 static int felix_tag_8021q_rxvlan_add(struct felix *felix, int port, u16 vid,
 				      bool pvid, bool untagged)
 {
diff --git a/drivers/net/dsa/ocelot/felix_tag_8021q.h b/drivers/net/dsa/ocelot/felix_tag_8021q.h
index a3501904e748..5080351cdb93 100644
--- a/drivers/net/dsa/ocelot/felix_tag_8021q.h
+++ b/drivers/net/dsa/ocelot/felix_tag_8021q.h
@@ -7,6 +7,7 @@
 #if IS_ENABLED(CONFIG_NET_DSA_TAG_OCELOT_8021Q)
 
 int felix_setup_8021q_tagging(struct ocelot *ocelot);
+bool felix_check_xtr_pkt(struct ocelot *ocelot, unsigned int ptp_type);
 
 #else
 
@@ -15,6 +16,12 @@ static inline int felix_setup_8021q_tagging(struct ocelot *ocelot)
 	return -EOPNOTSUPP;
 }
 
+static inline bool felix_check_xtr_pkt(struct ocelot *ocelot,
+				       unsigned int ptp_type)
+{
+	return false;
+}
+
 #endif /* IS_ENABLED(CONFIG_NET_DSA_TAG_OCELOT_8021Q) */
 
 #endif /* _MSCC_FELIX_TAG_8021Q_H */
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index ac6b9942052a..bb60382021e2 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -646,6 +646,7 @@ int ocelot_xtr_poll_xfh(struct ocelot *ocelot, int grp,
 
 	return 0;
 }
+EXPORT_SYMBOL(ocelot_xtr_poll_xfh);
 
 int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp,
 			  struct net_device *dev,
@@ -723,6 +724,7 @@ int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp,
 out:
 	return err;
 }
+EXPORT_SYMBOL(ocelot_xtr_poll_frame);
 
 /* Generate the IFH for frame injection
  *
@@ -801,6 +803,7 @@ void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
 	skb->dev->stats.tx_packets++;
 	skb->dev->stats.tx_bytes += skb->len;
 }
+EXPORT_SYMBOL(ocelot_port_inject_frame);
 
 int ocelot_fdb_add(struct ocelot *ocelot, int port,
 		   const unsigned char *addr, u16 vid)
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 04d0ba1e385e..d42aa229239e 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -119,14 +119,6 @@ int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
 void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port);
 
 bool ocelot_can_inject(struct ocelot *ocelot, int grp);
-void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
-			      u32 rew_op, struct sk_buff *skb);
-int ocelot_xtr_poll_xfh(struct ocelot *ocelot, int grp,
-			struct ocelot_frame_info *info);
-int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp,
-			  struct net_device *dev,
-			  struct ocelot_frame_info *info,
-			  struct sk_buff **skb);
 
 extern struct notifier_block ocelot_netdevice_nb;
 extern struct notifier_block ocelot_switchdev_nb;
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index ba803afcc55c..fa60ab5239d7 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -840,4 +840,13 @@ int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,
 				   enum devlink_sb_pool_type pool_type,
 				   u32 *p_cur, u32 *p_max);
 
+void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
+			      u32 rew_op, struct sk_buff *skb);
+int ocelot_xtr_poll_xfh(struct ocelot *ocelot, int grp,
+			struct ocelot_frame_info *info);
+int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp,
+			  struct net_device *dev,
+			  struct ocelot_frame_info *info,
+			  struct sk_buff **skb);
+
 #endif
diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c
index 430d77d0b8eb..a829d73d392b 100644
--- a/net/dsa/tag_ocelot_8021q.c
+++ b/net/dsa/tag_ocelot_8021q.c
@@ -2,6 +2,8 @@
 /* Copyright 2020-2021 NXP Semiconductors
  */
 #include <linux/dsa/8021q.h>
+#include <soc/mscc/ocelot.h>
+#include <soc/mscc/ocelot_ptp.h>
 #include "dsa_priv.h"
 
 static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
@@ -11,6 +13,28 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
 	u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
 	u16 queue_mapping = skb_get_queue_mapping(skb);
 	u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
+	struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
+
+	/* TX timestamping was requested, so inject through MMIO */
+	if (clone) {
+		struct ocelot *ocelot = dp->ds->priv;
+		struct ocelot_port *ocelot_port;
+		int port = dp->index;
+		u32 rew_op;
+
+		ocelot_port = ocelot->ports[port];
+		rew_op = ocelot_port->ptp_cmd;
+
+		/* Retrieve timestamp ID populated inside skb->cb[0] of the
+		 * clone by ocelot_port_add_txtstamp_skb
+		 */
+		if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
+			rew_op |= clone->cb[0] << 3;
+
+		ocelot_port_inject_frame(ocelot, dp->index, 0, rew_op, skb);
+
+		return NULL;
+	}
 
 	return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q,
 			      ((pcp << VLAN_PRIO_SHIFT) | tx_vid));
-- 
2.25.1


      parent reply	other threads:[~2021-01-18 16:20 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-18 16:17 [PATCH v3 net-next 00/15] tag_8021q for Ocelot switches Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 01/15] net: dsa: tag_8021q: add helpers to deduce whether a VLAN ID is RX or TX VLAN Vladimir Oltean
2021-01-18 17:57   ` Florian Fainelli
2021-01-18 16:17 ` [PATCH v3 net-next 02/15] net: mscc: ocelot: export VCAP structures to include/soc/mscc Vladimir Oltean
2021-01-18 17:58   ` Florian Fainelli
2021-01-18 16:17 ` [PATCH v3 net-next 03/15] net: mscc: ocelot: store a namespaced VCAP filter ID Vladimir Oltean
2021-01-18 18:00   ` Florian Fainelli
2021-01-18 16:17 ` [PATCH v3 net-next 04/15] net: dsa: felix: add new VLAN-based tagger Vladimir Oltean
2021-01-19  0:04   ` Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 05/15] net: mscc: ocelot: stop returning IRQ_NONE in ocelot_xtr_irq_handler Vladimir Oltean
2021-01-18 21:09   ` Florian Fainelli
2021-01-18 16:17 ` [PATCH v3 net-next 06/15] net: mscc: ocelot: only drain extraction queue on error Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 07/15] net: mscc: ocelot: just flush the CPU extraction group " Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 08/15] net: mscc: ocelot: better error handling in ocelot_xtr_irq_handler Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 09/15] net: mscc: ocelot: use DIV_ROUND_UP helper in ocelot_port_inject_frame Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 10/15] net: mscc: ocelot: refactor ocelot_port_inject_frame out of ocelot_port_xmit Vladimir Oltean
2021-01-18 20:15   ` Vladimir Oltean
2021-01-19  0:51   ` kernel test robot
2021-01-18 16:17 ` [PATCH v3 net-next 11/15] net: mscc: ocelot: export struct ocelot_frame_info Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 12/15] net: mscc: ocelot: refactor ocelot_xtr_irq_handler into ocelot_xtr_poll Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 13/15] net: dsa: felix: setup MMIO filtering rules for PTP when using tag_8021q Vladimir Oltean
2021-01-18 16:17 ` [PATCH v3 net-next 14/15] net: dsa: felix: use promisc on master for PTP with tag_8021q Vladimir Oltean
2021-01-18 16:17 ` Vladimir Oltean [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210118161731.2837700-16-olteanv@gmail.com \
    --to=olteanv@gmail.com \
    --cc=UNGLinuxDriver@microchip.com \
    --cc=al@b4comtech.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=alexandru.marginean@nxp.com \
    --cc=andrew@lunn.ch \
    --cc=claudiu.manoil@nxp.com \
    --cc=davem@davemloft.net \
    --cc=eldargasanov2@gmail.com \
    --cc=f.fainelli@gmail.com \
    --cc=fido_max@inbox.ru \
    --cc=hongbo.wang@nxp.com \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=po.liu@nxp.com \
    --cc=richardcochran@gmail.com \
    --cc=vivien.didelot@gmail.com \
    --cc=xiaoliang.yang_1@nxp.com \
    --cc=yangbo.lu@nxp.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).