Manually merged:
  backport-5.4
     011-kbuild-export-SUBARCH.patch
  layerscape
    701-net-0262-net-dsa-ocelot-add-tagger-for-Ocelot-Felix-switches.patch
All other modifications made by update_kernel.sh
Build-tested: x86/64, lantiq/xrx200, ramips/mt7621
Run-tested: ipq806x (R7800), lantiq/xrx200, x86/64, ramips (RT-AC57U)
No dmesg regressions, everything functional
Signed-off-by: John Audia <graysky@archlinux.us>
[minor commit message adjustments]
Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
		
	
		
			
				
	
	
		
			672 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			672 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 36b446d44d66a6d6a072d3f5e87ebb05e0b88d98 Mon Sep 17 00:00:00 2001
 | 
						|
From: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
 | 
						|
Date: Fri, 29 Nov 2019 14:28:37 +0800
 | 
						|
Subject: [PATCH] net: dsa: ocelot: add tsn support for felix switch
 | 
						|
 | 
						|
Support tsn capabilities in DSA felix switch driver. This felix tsn
 | 
						|
driver is using tsn configuration of ocelot, and registered on each
 | 
						|
switch port through DSA port setup.
 | 
						|
 | 
						|
Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
 | 
						|
---
 | 
						|
 drivers/net/dsa/ocelot/Kconfig         |   8 +
 | 
						|
 drivers/net/dsa/ocelot/Makefile        |   2 +
 | 
						|
 drivers/net/dsa/ocelot/felix.c         |  50 ++++
 | 
						|
 drivers/net/dsa/ocelot/felix_tsn.c     | 432 +++++++++++++++++++++++++++++++++
 | 
						|
 drivers/net/dsa/ocelot/felix_tsn.h     |  61 +++++
 | 
						|
 drivers/net/dsa/ocelot/felix_vsc9959.c |   8 +-
 | 
						|
 include/net/dsa.h                      |   1 +
 | 
						|
 net/dsa/dsa2.c                         |   4 +
 | 
						|
 8 files changed, 564 insertions(+), 2 deletions(-)
 | 
						|
 create mode 100644 drivers/net/dsa/ocelot/felix_tsn.c
 | 
						|
 create mode 100644 drivers/net/dsa/ocelot/felix_tsn.h
 | 
						|
 | 
						|
--- a/drivers/net/dsa/ocelot/Kconfig
 | 
						|
+++ b/drivers/net/dsa/ocelot/Kconfig
 | 
						|
@@ -9,3 +9,11 @@ config NET_DSA_MSCC_FELIX
 | 
						|
 	  the Vitesse / Microsemi / Microchip Ocelot family of switching cores.
 | 
						|
 	  It is embedded as a PCIe function of the NXP LS1028A ENETC integrated
 | 
						|
 	  endpoint.
 | 
						|
+
 | 
						|
+config MSCC_FELIX_SWITCH_TSN
 | 
						|
+	tristate "TSN on FELIX switch driver"
 | 
						|
+	depends on NET_DSA_MSCC_FELIX
 | 
						|
+	depends on TSN
 | 
						|
+	help
 | 
						|
+	  This driver supports TSN on felix switch.
 | 
						|
+
 | 
						|
--- a/drivers/net/dsa/ocelot/Makefile
 | 
						|
+++ b/drivers/net/dsa/ocelot/Makefile
 | 
						|
@@ -4,3 +4,5 @@ obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc
 | 
						|
 mscc_felix-objs := \
 | 
						|
 	felix.o \
 | 
						|
 	felix_vsc9959.o
 | 
						|
+
 | 
						|
+obj-$(CONFIG_MSCC_FELIX_SWITCH_TSN) += felix_tsn.o
 | 
						|
--- a/drivers/net/dsa/ocelot/felix.c
 | 
						|
+++ b/drivers/net/dsa/ocelot/felix.c
 | 
						|
@@ -9,6 +9,38 @@
 | 
						|
 #include <linux/of.h>
 | 
						|
 #include <net/dsa.h>
 | 
						|
 #include "felix.h"
 | 
						|
+#include "felix_tsn.h"
 | 
						|
+
 | 
						|
+#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
 | 
						|
+const struct tsn_ops switch_tsn_ops = {
 | 
						|
+	.device_init			= felix_tsn_init,
 | 
						|
+	.get_capability                 = felix_tsn_get_cap,
 | 
						|
+	.qbv_set			= felix_qbv_set,
 | 
						|
+	.qbv_get			= felix_qbv_get,
 | 
						|
+	.qbv_get_status			= felix_qbv_get_status,
 | 
						|
+	.qbu_set			= felix_qbu_set,
 | 
						|
+	.qbu_get                        = felix_qbu_get,
 | 
						|
+	.cb_streamid_set		= felix_cb_streamid_set,
 | 
						|
+	.cb_streamid_get		= felix_cb_streamid_get,
 | 
						|
+	.cb_streamid_counters_get	= felix_cb_streamid_counters_get,
 | 
						|
+	.qci_sfi_set			= felix_qci_sfi_set,
 | 
						|
+	.qci_sfi_get			= felix_qci_sfi_get,
 | 
						|
+	.qci_sfi_counters_get		= felix_qci_sfi_counters_get,
 | 
						|
+	.qci_get_maxcap			= felix_qci_max_cap_get,
 | 
						|
+	.qci_sgi_set			= felix_qci_sgi_set,
 | 
						|
+	.qci_sgi_get			= felix_qci_sgi_get,
 | 
						|
+	.qci_sgi_status_get		= felix_qci_sgi_status_get,
 | 
						|
+	.qci_fmi_set			= felix_qci_fmi_set,
 | 
						|
+	.qci_fmi_get			= felix_qci_fmi_get,
 | 
						|
+	.cbs_set			= felix_cbs_set,
 | 
						|
+	.cbs_get			= felix_cbs_get,
 | 
						|
+	.ct_set				= felix_cut_thru_set,
 | 
						|
+	.cbgen_set			= felix_seq_gen_set,
 | 
						|
+	.cbrec_set			= felix_seq_rec_set,
 | 
						|
+	.cb_get				= felix_cb_get,
 | 
						|
+	.dscp_set			= felix_dscp_set,
 | 
						|
+};
 | 
						|
+#endif
 | 
						|
 
 | 
						|
 static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,
 | 
						|
 						    int port)
 | 
						|
@@ -138,6 +170,21 @@ static int felix_vlan_del(struct dsa_swi
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
+#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
 | 
						|
+static int felix_tsn_enable(struct dsa_port *dp)
 | 
						|
+{
 | 
						|
+	struct net_device *dev;
 | 
						|
+
 | 
						|
+	if (dp->type == DSA_PORT_TYPE_USER) {
 | 
						|
+		dev = dp->slave;
 | 
						|
+		tsn_port_register(dev,
 | 
						|
+				  (struct tsn_ops *)&switch_tsn_ops,
 | 
						|
+				  GROUP_OFFSET_SWITCH);
 | 
						|
+	}
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 static int felix_port_enable(struct dsa_switch *ds, int port,
 | 
						|
 			     struct phy_device *phy)
 | 
						|
 {
 | 
						|
@@ -386,6 +433,9 @@ static const struct dsa_switch_ops felix
 | 
						|
 	.port_hwtstamp_set	= felix_hwtstamp_set,
 | 
						|
 	.port_rxtstamp		= felix_rxtstamp,
 | 
						|
 	.port_txtstamp		= felix_txtstamp,
 | 
						|
+#ifdef CONFIG_MSCC_FELIX_SWITCH_TSN
 | 
						|
+	.port_tsn_enable	= felix_tsn_enable,
 | 
						|
+#endif
 | 
						|
 };
 | 
						|
 
 | 
						|
 static struct felix_info *felix_instance_tbl[] = {
 | 
						|
--- /dev/null
 | 
						|
+++ b/drivers/net/dsa/ocelot/felix_tsn.c
 | 
						|
@@ -0,0 +1,432 @@
 | 
						|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
 | 
						|
+/* Felix Switch TSN driver
 | 
						|
+ *
 | 
						|
+ * Copyright 2018-2019 NXP
 | 
						|
+ */
 | 
						|
+
 | 
						|
+#include <linux/io.h>
 | 
						|
+#include <linux/module.h>
 | 
						|
+#include <linux/kernel.h>
 | 
						|
+#include <linux/pci.h>
 | 
						|
+#include <soc/mscc/ocelot.h>
 | 
						|
+#include <net/tsn.h>
 | 
						|
+#include "felix.h"
 | 
						|
+
 | 
						|
+static struct ocelot *felix_dev_to_ocelot(struct net_device *ndev)
 | 
						|
+{
 | 
						|
+	struct pci_dev *pdev;
 | 
						|
+	struct felix *felix;
 | 
						|
+
 | 
						|
+	pdev = list_entry(ndev->dev.parent, struct pci_dev, dev);
 | 
						|
+	felix = pci_get_drvdata(pdev);
 | 
						|
+	if (!felix)
 | 
						|
+		return NULL;
 | 
						|
+
 | 
						|
+	return &felix->ocelot;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static int felix_dev_to_port(struct net_device *ndev, struct ocelot *ocelot)
 | 
						|
+{
 | 
						|
+	struct felix *felix = ocelot_to_felix(ocelot);
 | 
						|
+	struct dsa_switch *ds = felix->ds;
 | 
						|
+	struct dsa_port *dp;
 | 
						|
+	int i;
 | 
						|
+
 | 
						|
+	for (i = 0; i < ds->num_ports; i++) {
 | 
						|
+		dp = &ds->ports[i];
 | 
						|
+		if (dp->dn == ndev->dev.of_node)
 | 
						|
+			return dp->index;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	return -ENODEV;
 | 
						|
+}
 | 
						|
+
 | 
						|
+u32 felix_tsn_get_cap(struct net_device *ndev)
 | 
						|
+{
 | 
						|
+	u32 cap = 0;
 | 
						|
+
 | 
						|
+	cap = (TSN_CAP_QBV | TSN_CAP_QCI | TSN_CAP_QBU | TSN_CAP_CBS |
 | 
						|
+	       TSN_CAP_CB | TSN_CAP_TBS | TSN_CAP_CTH);
 | 
						|
+
 | 
						|
+	return cap;
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qbv_set(struct net_device *ndev,
 | 
						|
+		  struct tsn_qbv_conf *shaper_config)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qbv_set(ocelot, port, shaper_config);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qbv_get(struct net_device *ndev,
 | 
						|
+		  struct tsn_qbv_conf *shaper_config)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qbv_get(ocelot, port, shaper_config);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qbv_get_status(struct net_device *ndev,
 | 
						|
+			 struct tsn_qbv_status *qbvstatus)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qbv_get_status(ocelot, port, qbvstatus);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qbu_set(struct net_device *ndev, u8 preemptible)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qbu_set(ocelot, port, preemptible);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qbu_get(struct net_device *ndev, struct tsn_preempt_status *c)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qbu_get(ocelot, port, c);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_cb_streamid_set(struct net_device *ndev, u32 index, bool enable,
 | 
						|
+			  struct tsn_cb_streamid *streamid)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_cb_streamid_set(ocelot, port, index, enable, streamid);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_cb_streamid_get(struct net_device *ndev, u32 index,
 | 
						|
+			  struct tsn_cb_streamid *streamid)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_cb_streamid_get(ocelot, port, index, streamid);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
 | 
						|
+				   struct tsn_cb_streamid_counters *sc)
 | 
						|
+{
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_sfi_set(struct net_device *ndev, u32 index, bool enable,
 | 
						|
+		      struct tsn_qci_psfp_sfi_conf *sfi)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_sfi_set(ocelot, port, index, enable, sfi);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_sfi_get(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_sfi_conf *sfi)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_sfi_get(ocelot, port, index, sfi);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_sfi_counters_get(struct net_device *ndev, u32 index,
 | 
						|
+			       struct tsn_qci_psfp_sfi_counters *sfi_cnt)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_sfi_counters_get(ocelot, port, index, sfi_cnt);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_max_cap_get(struct net_device *ndev,
 | 
						|
+			  struct tsn_qci_psfp_stream_param *stream_para)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_max_cap_get(ocelot, stream_para);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_sgi_set(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_sgi_conf *sgi_conf)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_sgi_set(ocelot, port, index, sgi_conf);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_sgi_get(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_sgi_conf *sgi_conf)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_sgi_get(ocelot, port, index, sgi_conf);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_sgi_status_get(struct net_device *ndev, u32 index,
 | 
						|
+			     struct tsn_psfp_sgi_status *sgi_status)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_sgi_status_get(ocelot, port, index, sgi_status);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_fmi_set(struct net_device *ndev, u32 index,
 | 
						|
+		      bool enable, struct tsn_qci_psfp_fmi *fmi)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_fmi_set(ocelot, port, index, enable, fmi);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_qci_fmi_get(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_fmi *fmi,
 | 
						|
+		      struct tsn_qci_psfp_fmi_counters *counters)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_qci_fmi_get(ocelot, port, index, fmi, counters);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_cbs_set(struct net_device *ndev, u8 tc, u8 bw)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_cbs_set(ocelot, port, tc, bw);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_cbs_get(struct net_device *ndev, u8 tc)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_cbs_get(ocelot, port, tc);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_cut_thru_set(struct net_device *ndev, u8 cut_thru)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_cut_thru_set(ocelot, port, cut_thru);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_seq_gen_set(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_seq_gen_conf *sg_conf)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_seq_gen_set(ocelot, port, index, sg_conf);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_seq_rec_set(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_seq_rec_conf *sr_conf)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_seq_rec_set(ocelot, port, index, sr_conf);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_cb_get(struct net_device *ndev, u32 index,
 | 
						|
+		 struct tsn_cb_status *c)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_cb_get(ocelot, port, index, c);
 | 
						|
+}
 | 
						|
+
 | 
						|
+int felix_dscp_set(struct net_device *ndev, bool enable, const u8 dscp_ix,
 | 
						|
+		   struct tsn_qos_switch_dscp_conf *c)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return -ENODEV;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+	if (port < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return ocelot_dscp_set(ocelot, port, enable, dscp_ix, c);
 | 
						|
+}
 | 
						|
+
 | 
						|
+void felix_tsn_init(struct net_device *ndev)
 | 
						|
+{
 | 
						|
+	struct ocelot *ocelot;
 | 
						|
+	int port;
 | 
						|
+
 | 
						|
+	ocelot = felix_dev_to_ocelot(ndev);
 | 
						|
+	if (!ocelot)
 | 
						|
+		return;
 | 
						|
+	port = felix_dev_to_port(ndev, ocelot);
 | 
						|
+
 | 
						|
+	ocelot_pcp_map_enable(ocelot, port);
 | 
						|
+	ocelot_rtag_parse_enable(ocelot, port);
 | 
						|
+}
 | 
						|
--- /dev/null
 | 
						|
+++ b/drivers/net/dsa/ocelot/felix_tsn.h
 | 
						|
@@ -0,0 +1,61 @@
 | 
						|
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
 | 
						|
+ *
 | 
						|
+ * TSN_SWITCH driver
 | 
						|
+ *
 | 
						|
+ * Copyright 2018-2019 NXP
 | 
						|
+ */
 | 
						|
+
 | 
						|
+#ifndef _MSCC_FELIX_SWITCH_TSN_H_
 | 
						|
+#define _MSCC_FELIX_SWITCH_TSN_H_
 | 
						|
+#include <net/tsn.h>
 | 
						|
+
 | 
						|
+u32 felix_tsn_get_cap(struct net_device *ndev);
 | 
						|
+int felix_qbv_set(struct net_device *ndev,
 | 
						|
+		  struct tsn_qbv_conf *shaper_config);
 | 
						|
+int felix_qbv_get(struct net_device *ndev,
 | 
						|
+		  struct tsn_qbv_conf *shaper_config);
 | 
						|
+int felix_qbv_get_status(struct net_device *ndev,
 | 
						|
+			 struct tsn_qbv_status *qbvstatus);
 | 
						|
+int felix_cut_thru_set(struct net_device *ndev, u8 cut_thru);
 | 
						|
+int felix_cbs_set(struct net_device *ndev, u8 tc, u8 bw);
 | 
						|
+int felix_cbs_get(struct net_device *ndev, u8 tc);
 | 
						|
+int felix_qbu_set(struct net_device *ndev, u8 preemptible);
 | 
						|
+int felix_qbu_get(struct net_device *ndev, struct tsn_preempt_status *c);
 | 
						|
+int felix_cb_streamid_get(struct net_device *ndev, u32 index,
 | 
						|
+			  struct tsn_cb_streamid *streamid);
 | 
						|
+int felix_cb_streamid_set(struct net_device *ndev, u32 index,
 | 
						|
+			  bool enable, struct tsn_cb_streamid *streamid);
 | 
						|
+int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
 | 
						|
+				   struct tsn_cb_streamid_counters *sc);
 | 
						|
+int felix_qci_sfi_get(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_sfi_conf *sfi);
 | 
						|
+int felix_qci_sfi_set(struct net_device *ndev, u32 index,
 | 
						|
+		      bool enable, struct tsn_qci_psfp_sfi_conf *sfi);
 | 
						|
+int felix_cb_streamid_counters_get(struct net_device *ndev, u32 index,
 | 
						|
+				   struct tsn_cb_streamid_counters *s_counters);
 | 
						|
+int felix_qci_sfi_counters_get(struct net_device *ndev, u32 index,
 | 
						|
+			       struct tsn_qci_psfp_sfi_counters *sfi_counters);
 | 
						|
+int felix_qci_max_cap_get(struct net_device *ndev,
 | 
						|
+			  struct tsn_qci_psfp_stream_param *stream_para);
 | 
						|
+int felix_qci_sgi_set(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_sgi_conf *sgi_conf);
 | 
						|
+int felix_qci_sgi_get(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_sgi_conf *sgi_conf);
 | 
						|
+int felix_qci_sgi_status_get(struct net_device *ndev, u16 index,
 | 
						|
+			     struct tsn_psfp_sgi_status *sgi_status);
 | 
						|
+int felix_qci_fmi_set(struct net_device *ndev, u32 index,
 | 
						|
+		      bool enable, struct tsn_qci_psfp_fmi *fmi);
 | 
						|
+int felix_qci_fmi_get(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_qci_psfp_fmi *fmi,
 | 
						|
+		      struct tsn_qci_psfp_fmi_counters *counters);
 | 
						|
+int felix_seq_gen_set(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_seq_gen_conf *sg_conf);
 | 
						|
+int felix_seq_rec_set(struct net_device *ndev, u32 index,
 | 
						|
+		      struct tsn_seq_rec_conf *sr_conf);
 | 
						|
+int felix_cb_get(struct net_device *ndev, u32 index,
 | 
						|
+		 struct tsn_cb_status  *c);
 | 
						|
+int felix_dscp_set(struct net_device *ndev, bool enable, const u8 dscp_ix,
 | 
						|
+		   struct tsn_qos_switch_dscp_conf *c);
 | 
						|
+
 | 
						|
+void felix_tsn_init(struct net_device *ndev);
 | 
						|
+#endif
 | 
						|
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
 | 
						|
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
 | 
						|
@@ -176,7 +176,7 @@ static const u32 vsc9959_qsys_regmap[] =
 | 
						|
 	REG(QSYS_QMAXSDU_CFG_6,			0x00f62c),
 | 
						|
 	REG(QSYS_QMAXSDU_CFG_7,			0x00f648),
 | 
						|
 	REG(QSYS_PREEMPTION_CFG,		0x00f664),
 | 
						|
-	REG_RESERVED(QSYS_CIR_CFG),
 | 
						|
+	REG(QSYS_CIR_CFG,			0x000000),
 | 
						|
 	REG(QSYS_EIR_CFG,			0x000004),
 | 
						|
 	REG(QSYS_SE_CFG,			0x000008),
 | 
						|
 	REG(QSYS_SE_DWRR_CFG,			0x00000c),
 | 
						|
@@ -269,7 +269,7 @@ static const u32 vsc9959_sys_regmap[] =
 | 
						|
 	REG_RESERVED(SYS_MMGT_FAST),
 | 
						|
 	REG_RESERVED(SYS_EVENTS_DIF),
 | 
						|
 	REG_RESERVED(SYS_EVENTS_CORE),
 | 
						|
-	REG_RESERVED(SYS_CNT),
 | 
						|
+	REG(SYS_CNT,				0x000000),
 | 
						|
 	REG(SYS_PTP_STATUS,			0x000f14),
 | 
						|
 	REG(SYS_PTP_TXSTAMP,			0x000f18),
 | 
						|
 	REG(SYS_PTP_NXT,			0x000f1c),
 | 
						|
@@ -290,6 +290,10 @@ static const u32 vsc9959_ptp_regmap[] =
 | 
						|
 	REG(PTP_CFG_MISC,                  0x0000a0),
 | 
						|
 	REG(PTP_CLK_CFG_ADJ_CFG,           0x0000a4),
 | 
						|
 	REG(PTP_CLK_CFG_ADJ_FREQ,          0x0000a8),
 | 
						|
+	REG(PTP_CUR_NSF,                   0x0000bc),
 | 
						|
+	REG(PTP_CUR_NSEC,                  0x0000c0),
 | 
						|
+	REG(PTP_CUR_SEC_LSB,               0x0000c4),
 | 
						|
+	REG(PTP_CUR_SEC_MSB,               0x0000c8),
 | 
						|
 };
 | 
						|
 
 | 
						|
 static const u32 vsc9959_gcb_regmap[] = {
 | 
						|
--- a/include/net/dsa.h
 | 
						|
+++ b/include/net/dsa.h
 | 
						|
@@ -554,6 +554,7 @@ struct dsa_switch_ops {
 | 
						|
 	 */
 | 
						|
 	netdev_tx_t (*port_deferred_xmit)(struct dsa_switch *ds, int port,
 | 
						|
 					  struct sk_buff *skb);
 | 
						|
+	int	(*port_tsn_enable)(struct dsa_port *dp);
 | 
						|
 };
 | 
						|
 
 | 
						|
 struct dsa_switch_driver {
 | 
						|
--- a/net/dsa/dsa2.c
 | 
						|
+++ b/net/dsa/dsa2.c
 | 
						|
@@ -323,6 +323,10 @@ static int dsa_port_setup(struct dsa_por
 | 
						|
 		if (err)
 | 
						|
 			break;
 | 
						|
 
 | 
						|
+		/* Enable TSN function on switch port */
 | 
						|
+		if (ds->ops->port_tsn_enable)
 | 
						|
+			ds->ops->port_tsn_enable(dp);
 | 
						|
+
 | 
						|
 		devlink_port_type_eth_set(dlp, dp->slave);
 | 
						|
 		break;
 | 
						|
 	}
 |