linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
@ 2019-11-11  4:41 Po Liu
  2019-11-11  4:41 ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
                   ` (7 more replies)
  0 siblings, 8 replies; 36+ messages in thread
From: Po Liu @ 2019-11-11  4:41 UTC (permalink / raw)
  To: Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC supports in hardware for time-based egress shaping according
to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
hardware offload method qdisc tc-taprio method.
Also update cbdr writeback to up level since control bd ring may
writeback data to control bd ring.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Singed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/Makefile |   1 +
 drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
 drivers/net/ethernet/freescale/enetc/enetc.h  |   2 +
 .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
 .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
 6 files changed, 285 insertions(+), 22 deletions(-)
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c

diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index d200c27c3bf6..389f722efc43 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -5,6 +5,7 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
 obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
 fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
 fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
+fsl-enetc-$(CONFIG_NET_SCH_TAPRIO) += enetc_qos.o
 
 obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
 fsl-enetc-vf-y := enetc_vf.o $(common-objs)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 3e8f9819f08c..d58dbc2c4270 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
 	return 0;
 }
 
-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
-		   void *type_data)
+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct tc_mqprio_qopt *mqprio = type_data;
@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	u8 num_tc;
 	int i;
 
-	if (type != TC_SETUP_QDISC_MQPRIO)
-		return -EOPNOTSUPP;
-
 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
 	num_tc = mqprio->num_tc;
 
@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	return 0;
 }
 
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+		   void *type_data)
+{
+	switch (type) {
+	case TC_SETUP_QDISC_MQPRIO:
+		return enetc_setup_tc_mqprio(ndev, type_data);
+	case TC_SETUP_QDISC_TAPRIO:
+		return enetc_setup_tc_taprio(ndev, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 struct net_device_stats *enetc_get_stats(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 541b4e2073fe..8676631041d5 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -244,3 +244,5 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
 void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
index de466b71bf8f..201cbc362e33 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
 		r->bd_count;
 }
 
-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 {
 	struct enetc_cbdr *ring = &si->cbd_ring;
 	int timeout = ENETC_CBDR_TIMEOUT;
@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 	if (!timeout)
 		return -EBUSY;
 
+	/* CBD may writeback data, feedback up level */
+	*cbd = *dest_cbd;
+
 	enetc_clean_cbdr(si);
 
 	return 0;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 88276299f447..75a7c0f1f8ce 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -18,6 +18,7 @@
 #define ENETC_SICTR0	0x18
 #define ENETC_SICTR1	0x1c
 #define ENETC_SIPCAPR0	0x20
+#define ENETC_SIPCAPR0_QBV	BIT(4)
 #define ENETC_SIPCAPR0_RSS	BIT(8)
 #define ENETC_SIPCAPR1	0x24
 #define ENETC_SITGTGR	0x30
@@ -148,6 +149,12 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PORT_BASE		0x10000
 #define ENETC_PMR		0x0000
 #define ENETC_PMR_EN	GENMASK(18, 16)
+#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
+#define ENETC_PMR_PSPEED_10M 0x000
+#define ENETC_PMR_PSPEED_100M 0x100
+#define ENETC_PMR_PSPEED_1000M 0x200
+#define ENETC_PMR_PSPEED_2500M 0x400
+
 #define ENETC_PSR		0x0004 /* RO */
 #define ENETC_PSIPMR		0x0018
 #define ENETC_PSIPMR_SET_UP(n)	BIT(n) /* n = SI index */
@@ -440,22 +447,6 @@ union enetc_rx_bd {
 #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
 #define ENETC_MAX_NUM_VFS	2
 
-struct enetc_cbd {
-	union {
-		struct {
-			__le32 addr[2];
-			__le32 opt[4];
-		};
-		__le32 data[6];
-	};
-	__le16 index;
-	__le16 length;
-	u8 cmd;
-	u8 cls;
-	u8 _res;
-	u8 status_flags;
-};
-
 #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
 #define ENETC_CBD_STATUS_MASK	0xf
 
@@ -554,3 +545,130 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
 	val |= ENETC_TBMR_SET_PRIO(prio);
 	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
 }
+
+enum bdcr_cmd_class {
+	BDCR_CMD_UNSPEC = 0,
+	BDCR_CMD_MAC_FILTER,
+	BDCR_CMD_VLAN_FILTER,
+	BDCR_CMD_RSS,
+	BDCR_CMD_RFS,
+	BDCR_CMD_PORT_GCL,
+	BDCR_CMD_RECV_CLASSIFIER,
+	__BDCR_CMD_MAX_LEN,
+	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
+};
+
+/* class 5, command 0 */
+struct tgs_gcl_conf {
+	u8	atc;	/* init gate value */
+	u8	res[7];
+	union {
+		struct {
+			u8	res1[4];
+			__le16	acl_len;
+			u8	res2[2];
+		};
+		struct {
+			u32 cctl;
+			u32 ccth;
+		};
+	};
+};
+
+#define ENETC_CBDR_SGL_IOMEN	BIT(0)
+#define ENETC_CBDR_SGL_IPVEN	BIT(3)
+#define ENETC_CBDR_SGL_GTST	BIT(4)
+#define ENETC_CBDR_SGL_IPV_MASK 0xe
+
+/* gate control list entry */
+struct gce {
+	u32	period;
+	u8	gate;
+	u8	res[3];
+};
+
+/* tgs_gcl_conf address point to this data space */
+struct tgs_gcl_data {
+	u32	btl;
+	u32	bth;
+	u32	ct;
+	u32	cte;
+};
+
+/* class 5, command 1 */
+struct tgs_gcl_query {
+		u8	res[12];
+		union {
+			struct {
+				__le16	acl_len; /* admin list length */
+				__le16	ocl_len; /* operation list length */
+			};
+			struct {
+				u16 admin_list_len;
+				u16 oper_list_len;
+			};
+		};
+};
+
+/* tgs_gcl_query command response data format */
+struct tgs_gcl_resp {
+	u32 abtl;	/* base time */
+	u32 abth;
+	u32 act;	/* cycle time */
+	u32 acte;	/* cycle time extend */
+	u32 cctl;	/* config change time */
+	u32 ccth;
+	u32 obtl;	/* operation base time */
+	u32 obth;
+	u32 oct;	/* operation cycle time */
+	u32 octe;	/* operation cycle time extend */
+	u32 ccel;	/* config change error */
+	u32 cceh;
+};
+
+struct enetc_cbd {
+	union{
+		struct {
+			__le32	addr[2];
+			union {
+				__le32	opt[4];
+				struct tgs_gcl_conf	gcl_conf;
+				struct tgs_gcl_query	gcl_query;
+			};
+		};	/* Long format */
+		__le32 data[6];
+	};
+	__le16 index;
+	__le16 length;
+	u8 cmd;
+	u8 cls;
+	u8 _res;
+	u8 status_flags;
+};
+
+#define ENETC_PTCFPR(n)		(0x1910 + (n) * 4) /* n = [0 ..7] */
+#define ENETC_FPE		BIT(31)
+
+/* Port capability register 0 */
+#define ENETC_PCAPR0_PSFPM	BIT(10)
+#define ENETC_PCAPR0_PSFP	BIT(9)
+#define ENETC_PCAPR0_TSN	BIT(4)
+#define ENETC_PCAPR0_QBU	BIT(3)
+
+/* port time gating control register */
+#define ENETC_QBV_PTGCR_OFFSET		0x11a00
+#define ENETC_QBV_TGE			0x80000000
+#define ENETC_QBV_TGPE			BIT(30)
+#define ENETC_QBV_TGDROP_DISABLE	BIT(29)
+
+/* Port time gating capability register */
+#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
+#define ENETC_QBV_MAX_GCL_LEN_MASK	0xffff
+
+/* Port time gating admin gate list status register */
+#define ENETC_QBV_PTGAGLSR_OFFSET	0x11a10
+#define ENETC_QBV_CFG_PEND_MASK	0x00000002
+
+#define ENETC_TGLSTR			0xa200
+#define ENETC_TGS_MIN_DIS_MASK		0x80000000
+#define ENETC_MIN_LOOKAHEAD_MASK	0xffff
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
new file mode 100644
index 000000000000..036bb39c7a0b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2019 NXP */
+
+#include "enetc.h"
+
+#include <net/pkt_sched.h>
+
+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+{
+	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
+		& ENETC_QBV_MAX_GCL_LEN_MASK;
+}
+
+static int enetc_setup_taprio(struct net_device *ndev,
+			      struct tc_taprio_qopt_offload *admin_conf)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_cbd cbd = {.cmd = 0};
+	struct tgs_gcl_conf *gcl_config;
+	struct tgs_gcl_data *gcl_data;
+	struct gce *gce;
+	dma_addr_t dma;
+	u16 data_size;
+	u16 gcl_len;
+	u32 temp;
+	int i;
+
+	gcl_len = admin_conf->num_entries;
+	if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
+		return -EINVAL;
+
+	if (admin_conf->enable) {
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 temp & (~ENETC_QBV_TGE));
+		usleep_range(10, 20);
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 temp | ENETC_QBV_TGE);
+	} else {
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 temp & (~ENETC_QBV_TGE));
+		return 0;
+	}
+
+	/* Configure the (administrative) gate control list using the
+	 * control BD descriptor.
+	 */
+	gcl_config = &cbd.gcl_conf;
+
+	data_size = sizeof(struct tgs_gcl_data) + gcl_len * sizeof(struct gce);
+
+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+	if (!gcl_data)
+		return -ENOMEM;
+
+	gce = (struct gce *)(gcl_data + 1);
+
+	/* Since no initial state config in taprio, set gates open as default.
+	 */
+	gcl_config->atc = 0xff;
+	gcl_config->acl_len = cpu_to_le16(gcl_len);
+
+	if (!admin_conf->base_time) {
+		gcl_data->btl =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
+		gcl_data->bth =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
+	} else {
+		gcl_data->btl =
+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
+		gcl_data->bth =
+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
+	}
+
+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
+
+	for (i = 0; i < gcl_len; i++) {
+		struct tc_taprio_sched_entry *temp_entry;
+		struct gce *temp_gce = gce + i;
+
+		temp_entry = &admin_conf->entries[i];
+
+		temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);
+		temp_gce->period = cpu_to_le32(temp_entry->interval);
+	}
+
+	cbd.length = cpu_to_le16(data_size);
+	cbd.status_flags = 0;
+
+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+			     data_size, DMA_TO_DEVICE);
+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+		kfree(gcl_data);
+		return -ENOMEM;
+	}
+
+	cbd.addr[0] = lower_32_bits(dma);
+	cbd.addr[1] = upper_32_bits(dma);
+	cbd.cls = BDCR_CMD_PORT_GCL;
+
+	/* Updated by ENETC on completion of the configuration
+	 * command. A zero value indicates success.
+	 */
+	cbd.status_flags = 0;
+
+	enetc_send_cmd(priv->si, &cbd);
+
+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
+	kfree(gcl_data);
+
+	return 0;
+}
+
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
+{
+	struct tc_taprio_qopt_offload *taprio = type_data;
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < priv->num_tx_rings; i++)
+		enetc_set_bdr_prio(&priv->si->hw,
+				   priv->tx_ring[i]->index,
+				   taprio->enable ? i : 0);
+
+	return enetc_setup_taprio(ndev, taprio);
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
@ 2019-11-11  4:41 ` Po Liu
  2019-11-12  8:42   ` [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
                     ` (2 more replies)
  2019-11-12  5:50 ` [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload David Miller
                   ` (6 subsequent siblings)
  7 siblings, 3 replies; 36+ messages in thread
From: Po Liu @ 2019-11-11  4:41 UTC (permalink / raw)
  To: Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC has a register PSPEED to indicate the link speed of hardware.
It is need to update accordingly. PSPEED field needs to be updated
with the port speed for QBV scheduling purposes. Or else there is
chance for gate slot not free by frame taking the MAC if PSPEED and
phy speed not match. So update PSPEED when link adjust. This is
implement by the adjust_link.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Singed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c  | 13 +++++--
 drivers/net/ethernet/freescale/enetc/enetc.h  |  7 ++++
 .../net/ethernet/freescale/enetc/enetc_pf.c   |  3 ++
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 34 +++++++++++++++++++
 4 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index d58dbc2c4270..f6b00c68451b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -742,9 +742,14 @@ void enetc_get_si_caps(struct enetc_si *si)
 	si->num_rss = 0;
 	val = enetc_rd(hw, ENETC_SIPCAPR0);
 	if (val & ENETC_SIPCAPR0_RSS) {
-		val = enetc_rd(hw, ENETC_SIRSSCAPR);
-		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val);
+		u32 rss;
+
+		rss = enetc_rd(hw, ENETC_SIRSSCAPR);
+		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
 	}
+
+	if (val & ENETC_SIPCAPR0_QBV)
+		si->hw_features |= ENETC_SI_F_QBV;
 }
 
 static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
@@ -1314,8 +1319,12 @@ static void enetc_disable_interrupts(struct enetc_ndev_priv *priv)
 
 static void adjust_link(struct net_device *ndev)
 {
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct phy_device *phydev = ndev->phydev;
 
+	if (priv->active_offloads & ENETC_F_QBV)
+		enetc_sched_speed_set(ndev);
+
 	phy_print_status(phydev);
 }
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 8676631041d5..e85e5301c578 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -118,6 +118,8 @@ enum enetc_errata {
 	ENETC_ERR_UCMCSWP	= BIT(2),
 };
 
+#define ENETC_SI_F_QBV  (1<<0)
+
 /* PCI IEP device data */
 struct enetc_si {
 	struct pci_dev *pdev;
@@ -133,6 +135,7 @@ struct enetc_si {
 	int num_fs_entries;
 	int num_rss; /* number of RSS buckets */
 	unsigned short pad;
+	int hw_features;
 };
 
 #define ENETC_SI_ALIGN	32
@@ -173,6 +176,7 @@ struct enetc_cls_rule {
 enum enetc_active_offloads {
 	ENETC_F_RX_TSTAMP	= BIT(0),
 	ENETC_F_TX_TSTAMP	= BIT(1),
+	ENETC_F_QBV             = BIT(2),
 };
 
 struct enetc_ndev_priv {
@@ -188,6 +192,8 @@ struct enetc_ndev_priv {
 	u16 msg_enable;
 	int active_offloads;
 
+	u32 speed; /* store speed for compare update pspeed */
+
 	struct enetc_bdr *tx_ring[16];
 	struct enetc_bdr *rx_ring[16];
 
@@ -246,3 +252,4 @@ int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
 int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
 int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+void enetc_sched_speed_set(struct net_device *ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 7da79b816416..e7482d483b28 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -742,6 +742,9 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 
 	ndev->priv_flags |= IFF_UNICAST_FLT;
 
+	if (si->hw_features & ENETC_SI_F_QBV)
+		priv->active_offloads |= ENETC_F_QBV;
+
 	/* pick up primary MAC address from SI */
 	enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
 }
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index 036bb39c7a0b..801104dd2ba6 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -11,6 +11,40 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
 		& ENETC_QBV_MAX_GCL_LEN_MASK;
 }
 
+void enetc_sched_speed_set(struct net_device *ndev)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct phy_device *phydev = ndev->phydev;
+	u32 old_speed = priv->speed;
+	u32 speed, pspeed;
+
+	if (phydev->speed == old_speed)
+		return;
+
+	speed = phydev->speed;
+	switch (speed) {
+	case SPEED_1000:
+		pspeed = ENETC_PMR_PSPEED_1000M;
+		break;
+	case SPEED_2500:
+		pspeed = ENETC_PMR_PSPEED_2500M;
+		break;
+	case SPEED_100:
+		pspeed = ENETC_PMR_PSPEED_100M;
+		break;
+	case SPEED_10:
+	default:
+		pspeed = ENETC_PMR_PSPEED_10M;
+		netdev_err(ndev, "Qbv PSPEED set speed link down.\n");
+	}
+
+	priv->speed = speed;
+	enetc_port_wr(&priv->si->hw, ENETC_PMR,
+		      (enetc_port_rd(&priv->si->hw, ENETC_PMR)
+		      & (~ENETC_PMR_PSPEED_MASK))
+		      | pspeed);
+}
+
 static int enetc_setup_taprio(struct net_device *ndev,
 			      struct tc_taprio_qopt_offload *admin_conf)
 {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-11  4:41 ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-12  5:50 ` David Miller
  2019-11-12  6:48   ` [EXT] " Po Liu
  2019-11-12  9:41 ` Simon Horman
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 36+ messages in thread
From: David Miller @ 2019-11-12  5:50 UTC (permalink / raw)
  To: po.liu
  Cc: claudiu.manoil, linux-kernel, netdev, vinicius.gomes,
	vladimir.oltean, alexandru.marginean, xiaoliang.yang_1, roy.zang,
	mingkai.hu, jerry.huang, leoyang.li

From: Po Liu <po.liu@nxp.com>
Date: Mon, 11 Nov 2019 04:41:26 +0000

> +fsl-enetc-$(CONFIG_NET_SCH_TAPRIO) += enetc_qos.o

Code is Kconfig guarded.
> +	case TC_SETUP_QDISC_TAPRIO:
> +		return enetc_setup_tc_taprio(ndev, type_data);

Yet invoked unconditionally.

I can see just by reading your code that various configurations will
result in link errors.

 ...
> +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
> +{
> +	struct tc_taprio_qopt_offload *taprio = type_data;
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +	int i;
> +
> +	for (i = 0; i < priv->num_tx_rings; i++)
> +		enetc_set_bdr_prio(&priv->si->hw,
> +				   priv->tx_ring[i]->index,
> +				   taprio->enable ? i : 0);
> +
> +	return enetc_setup_taprio(ndev, taprio);
> +}
> -- 
> 2.17.1
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12  5:50 ` [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload David Miller
@ 2019-11-12  6:48   ` Po Liu
  0 siblings, 0 replies; 36+ messages in thread
From: Po Liu @ 2019-11-12  6:48 UTC (permalink / raw)
  To: David Miller
  Cc: Claudiu Manoil, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

Hi David,


Br,
Po Liu

> -----Original Message-----
> From: David Miller <davem@redhat.com>
> Sent: 2019年11月12日 13:51
> To: Po Liu <po.liu@nxp.com>
> Cc: Claudiu Manoil <claudiu.manoil@nxp.com>; linux-kernel@vger.kernel.org;
> netdev@vger.kernel.org; vinicius.gomes@intel.com; Vladimir Oltean
> <vladimir.oltean@nxp.com>; Alexandru Marginean
> <alexandru.marginean@nxp.com>; Xiaoliang Yang
> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
> <leoyang.li@nxp.com>
> Subject: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via
> tc-taprio offload
> 
> Caution: EXT Email
> 
> From: Po Liu <po.liu@nxp.com>
> Date: Mon, 11 Nov 2019 04:41:26 +0000
> 
> > +fsl-enetc-$(CONFIG_NET_SCH_TAPRIO) += enetc_qos.o
> 
> Code is Kconfig guarded.
> > +     case TC_SETUP_QDISC_TAPRIO:
> > +             return enetc_setup_tc_taprio(ndev, type_data);
> 
> Yet invoked unconditionally.
> 
> I can see just by reading your code that various configurations will result in link
> errors.

I get it. Thanks!

> 
>  ...
> > +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) {
> > +     struct tc_taprio_qopt_offload *taprio = type_data;
> > +     struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > +     int i;
> > +
> > +     for (i = 0; i < priv->num_tx_rings; i++)
> > +             enetc_set_bdr_prio(&priv->si->hw,
> > +                                priv->tx_ring[i]->index,
> > +                                taprio->enable ? i : 0);
> > +
> > +     return enetc_setup_taprio(ndev, taprio); }
> > --
> > 2.17.1
> >


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-11  4:41 ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-12  8:42   ` Po Liu
  2019-11-12  8:42     ` [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
                       ` (2 more replies)
  2019-11-12  9:41   ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Simon Horman
  2019-11-12 19:59   ` kbuild test robot
  2 siblings, 3 replies; 36+ messages in thread
From: Po Liu @ 2019-11-12  8:42 UTC (permalink / raw)
  To: Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC supports in hardware for time-based egress shaping according
to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
hardware offload method qdisc tc-taprio method.
Also update cbdr writeback to up level since control bd ring may
writeback data to control bd ring.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
---
changes:
- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
  configurations will result in link errors.
  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
  tsn feature, or else, return not support.

 drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
 drivers/net/ethernet/freescale/enetc/Makefile |   1 +
 drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
 drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
 .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
 .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
 7 files changed, 300 insertions(+), 22 deletions(-)
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c

diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index c219587bd334..017ade2d0e50 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING
 	  allocation has not been supported and it is too expensive to use
 	  extended RX BDs if timestamping is not used, this option enables
 	  extended RX BDs in order to support hardware timestamping.
+
+config FSL_ENETC_QOS
+	bool "ENETC hardware Time-sensitive Network support"
+	depends on FSL_ENETC && NET_SCH_TAPRIO
+	help
+	  There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
+	  /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
+	  enable/disable from user space via Qos commands(tc). In the kernel
+	  side, it can be loaded by Qos driver. Currently, it is only support
+	  taprio(802.1Qbv).
diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index d200c27c3bf6..7a80680a7634 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -5,6 +5,7 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
 obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
 fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
 fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
+fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
 
 obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
 fsl-enetc-vf-y := enetc_vf.o $(common-objs)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 3e8f9819f08c..d58dbc2c4270 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
 	return 0;
 }
 
-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
-		   void *type_data)
+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct tc_mqprio_qopt *mqprio = type_data;
@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	u8 num_tc;
 	int i;
 
-	if (type != TC_SETUP_QDISC_MQPRIO)
-		return -EOPNOTSUPP;
-
 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
 	num_tc = mqprio->num_tc;
 
@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	return 0;
 }
 
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+		   void *type_data)
+{
+	switch (type) {
+	case TC_SETUP_QDISC_MQPRIO:
+		return enetc_setup_tc_mqprio(ndev, type_data);
+	case TC_SETUP_QDISC_TAPRIO:
+		return enetc_setup_tc_taprio(ndev, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 struct net_device_stats *enetc_get_stats(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 541b4e2073fe..8ca2f97050c8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
 void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
+
+#ifdef CONFIG_FSL_ENETC_QOS
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+#else
+#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+#endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
index de466b71bf8f..201cbc362e33 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
 		r->bd_count;
 }
 
-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 {
 	struct enetc_cbdr *ring = &si->cbd_ring;
 	int timeout = ENETC_CBDR_TIMEOUT;
@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 	if (!timeout)
 		return -EBUSY;
 
+	/* CBD may writeback data, feedback up level */
+	*cbd = *dest_cbd;
+
 	enetc_clean_cbdr(si);
 
 	return 0;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 88276299f447..75a7c0f1f8ce 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -18,6 +18,7 @@
 #define ENETC_SICTR0	0x18
 #define ENETC_SICTR1	0x1c
 #define ENETC_SIPCAPR0	0x20
+#define ENETC_SIPCAPR0_QBV	BIT(4)
 #define ENETC_SIPCAPR0_RSS	BIT(8)
 #define ENETC_SIPCAPR1	0x24
 #define ENETC_SITGTGR	0x30
@@ -148,6 +149,12 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PORT_BASE		0x10000
 #define ENETC_PMR		0x0000
 #define ENETC_PMR_EN	GENMASK(18, 16)
+#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
+#define ENETC_PMR_PSPEED_10M 0x000
+#define ENETC_PMR_PSPEED_100M 0x100
+#define ENETC_PMR_PSPEED_1000M 0x200
+#define ENETC_PMR_PSPEED_2500M 0x400
+
 #define ENETC_PSR		0x0004 /* RO */
 #define ENETC_PSIPMR		0x0018
 #define ENETC_PSIPMR_SET_UP(n)	BIT(n) /* n = SI index */
@@ -440,22 +447,6 @@ union enetc_rx_bd {
 #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
 #define ENETC_MAX_NUM_VFS	2
 
-struct enetc_cbd {
-	union {
-		struct {
-			__le32 addr[2];
-			__le32 opt[4];
-		};
-		__le32 data[6];
-	};
-	__le16 index;
-	__le16 length;
-	u8 cmd;
-	u8 cls;
-	u8 _res;
-	u8 status_flags;
-};
-
 #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
 #define ENETC_CBD_STATUS_MASK	0xf
 
@@ -554,3 +545,130 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
 	val |= ENETC_TBMR_SET_PRIO(prio);
 	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
 }
+
+enum bdcr_cmd_class {
+	BDCR_CMD_UNSPEC = 0,
+	BDCR_CMD_MAC_FILTER,
+	BDCR_CMD_VLAN_FILTER,
+	BDCR_CMD_RSS,
+	BDCR_CMD_RFS,
+	BDCR_CMD_PORT_GCL,
+	BDCR_CMD_RECV_CLASSIFIER,
+	__BDCR_CMD_MAX_LEN,
+	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
+};
+
+/* class 5, command 0 */
+struct tgs_gcl_conf {
+	u8	atc;	/* init gate value */
+	u8	res[7];
+	union {
+		struct {
+			u8	res1[4];
+			__le16	acl_len;
+			u8	res2[2];
+		};
+		struct {
+			u32 cctl;
+			u32 ccth;
+		};
+	};
+};
+
+#define ENETC_CBDR_SGL_IOMEN	BIT(0)
+#define ENETC_CBDR_SGL_IPVEN	BIT(3)
+#define ENETC_CBDR_SGL_GTST	BIT(4)
+#define ENETC_CBDR_SGL_IPV_MASK 0xe
+
+/* gate control list entry */
+struct gce {
+	u32	period;
+	u8	gate;
+	u8	res[3];
+};
+
+/* tgs_gcl_conf address point to this data space */
+struct tgs_gcl_data {
+	u32	btl;
+	u32	bth;
+	u32	ct;
+	u32	cte;
+};
+
+/* class 5, command 1 */
+struct tgs_gcl_query {
+		u8	res[12];
+		union {
+			struct {
+				__le16	acl_len; /* admin list length */
+				__le16	ocl_len; /* operation list length */
+			};
+			struct {
+				u16 admin_list_len;
+				u16 oper_list_len;
+			};
+		};
+};
+
+/* tgs_gcl_query command response data format */
+struct tgs_gcl_resp {
+	u32 abtl;	/* base time */
+	u32 abth;
+	u32 act;	/* cycle time */
+	u32 acte;	/* cycle time extend */
+	u32 cctl;	/* config change time */
+	u32 ccth;
+	u32 obtl;	/* operation base time */
+	u32 obth;
+	u32 oct;	/* operation cycle time */
+	u32 octe;	/* operation cycle time extend */
+	u32 ccel;	/* config change error */
+	u32 cceh;
+};
+
+struct enetc_cbd {
+	union{
+		struct {
+			__le32	addr[2];
+			union {
+				__le32	opt[4];
+				struct tgs_gcl_conf	gcl_conf;
+				struct tgs_gcl_query	gcl_query;
+			};
+		};	/* Long format */
+		__le32 data[6];
+	};
+	__le16 index;
+	__le16 length;
+	u8 cmd;
+	u8 cls;
+	u8 _res;
+	u8 status_flags;
+};
+
+#define ENETC_PTCFPR(n)		(0x1910 + (n) * 4) /* n = [0 ..7] */
+#define ENETC_FPE		BIT(31)
+
+/* Port capability register 0 */
+#define ENETC_PCAPR0_PSFPM	BIT(10)
+#define ENETC_PCAPR0_PSFP	BIT(9)
+#define ENETC_PCAPR0_TSN	BIT(4)
+#define ENETC_PCAPR0_QBU	BIT(3)
+
+/* port time gating control register */
+#define ENETC_QBV_PTGCR_OFFSET		0x11a00
+#define ENETC_QBV_TGE			0x80000000
+#define ENETC_QBV_TGPE			BIT(30)
+#define ENETC_QBV_TGDROP_DISABLE	BIT(29)
+
+/* Port time gating capability register */
+#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
+#define ENETC_QBV_MAX_GCL_LEN_MASK	0xffff
+
+/* Port time gating admin gate list status register */
+#define ENETC_QBV_PTGAGLSR_OFFSET	0x11a10
+#define ENETC_QBV_CFG_PEND_MASK	0x00000002
+
+#define ENETC_TGLSTR			0xa200
+#define ENETC_TGS_MIN_DIS_MASK		0x80000000
+#define ENETC_MIN_LOOKAHEAD_MASK	0xffff
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
new file mode 100644
index 000000000000..036bb39c7a0b
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2019 NXP */
+
+#include "enetc.h"
+
+#include <net/pkt_sched.h>
+
+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+{
+	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
+		& ENETC_QBV_MAX_GCL_LEN_MASK;
+}
+
+static int enetc_setup_taprio(struct net_device *ndev,
+			      struct tc_taprio_qopt_offload *admin_conf)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_cbd cbd = {.cmd = 0};
+	struct tgs_gcl_conf *gcl_config;
+	struct tgs_gcl_data *gcl_data;
+	struct gce *gce;
+	dma_addr_t dma;
+	u16 data_size;
+	u16 gcl_len;
+	u32 temp;
+	int i;
+
+	gcl_len = admin_conf->num_entries;
+	if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
+		return -EINVAL;
+
+	if (admin_conf->enable) {
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 temp & (~ENETC_QBV_TGE));
+		usleep_range(10, 20);
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 temp | ENETC_QBV_TGE);
+	} else {
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 temp & (~ENETC_QBV_TGE));
+		return 0;
+	}
+
+	/* Configure the (administrative) gate control list using the
+	 * control BD descriptor.
+	 */
+	gcl_config = &cbd.gcl_conf;
+
+	data_size = sizeof(struct tgs_gcl_data) + gcl_len * sizeof(struct gce);
+
+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+	if (!gcl_data)
+		return -ENOMEM;
+
+	gce = (struct gce *)(gcl_data + 1);
+
+	/* Since no initial state config in taprio, set gates open as default.
+	 */
+	gcl_config->atc = 0xff;
+	gcl_config->acl_len = cpu_to_le16(gcl_len);
+
+	if (!admin_conf->base_time) {
+		gcl_data->btl =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
+		gcl_data->bth =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
+	} else {
+		gcl_data->btl =
+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
+		gcl_data->bth =
+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
+	}
+
+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
+
+	for (i = 0; i < gcl_len; i++) {
+		struct tc_taprio_sched_entry *temp_entry;
+		struct gce *temp_gce = gce + i;
+
+		temp_entry = &admin_conf->entries[i];
+
+		temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);
+		temp_gce->period = cpu_to_le32(temp_entry->interval);
+	}
+
+	cbd.length = cpu_to_le16(data_size);
+	cbd.status_flags = 0;
+
+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+			     data_size, DMA_TO_DEVICE);
+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+		kfree(gcl_data);
+		return -ENOMEM;
+	}
+
+	cbd.addr[0] = lower_32_bits(dma);
+	cbd.addr[1] = upper_32_bits(dma);
+	cbd.cls = BDCR_CMD_PORT_GCL;
+
+	/* Updated by ENETC on completion of the configuration
+	 * command. A zero value indicates success.
+	 */
+	cbd.status_flags = 0;
+
+	enetc_send_cmd(priv->si, &cbd);
+
+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
+	kfree(gcl_data);
+
+	return 0;
+}
+
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
+{
+	struct tc_taprio_qopt_offload *taprio = type_data;
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < priv->num_tx_rings; i++)
+		enetc_set_bdr_prio(&priv->si->hw,
+				   priv->tx_ring[i]->index,
+				   taprio->enable ? i : 0);
+
+	return enetc_setup_taprio(ndev, taprio);
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-12  8:42   ` [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
@ 2019-11-12  8:42     ` Po Liu
  2019-11-12 18:57       ` David Miller
  2019-11-14  5:12       ` [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-12 18:57     ` [v2,net-next, " David Miller
  2019-11-12 21:10     ` Ivan Khoronzhuk
  2 siblings, 2 replies; 36+ messages in thread
From: Po Liu @ 2019-11-12  8:42 UTC (permalink / raw)
  To: Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC has a register PSPEED to indicate the link speed of hardware.
It is need to update accordingly. PSPEED field needs to be updated
with the port speed for QBV scheduling purposes. Or else there is
chance for gate slot not free by frame taking the MAC if PSPEED and
phy speed not match. So update PSPEED when link adjust. This is
implement by the adjust_link.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
changes:
- fix for enetc_sched_speed_set() define for different config.

 drivers/net/ethernet/freescale/enetc/enetc.c  | 13 +++++--
 drivers/net/ethernet/freescale/enetc/enetc.h  |  8 +++++
 .../net/ethernet/freescale/enetc/enetc_pf.c   |  3 ++
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 34 +++++++++++++++++++
 4 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index d58dbc2c4270..f6b00c68451b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -742,9 +742,14 @@ void enetc_get_si_caps(struct enetc_si *si)
 	si->num_rss = 0;
 	val = enetc_rd(hw, ENETC_SIPCAPR0);
 	if (val & ENETC_SIPCAPR0_RSS) {
-		val = enetc_rd(hw, ENETC_SIRSSCAPR);
-		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val);
+		u32 rss;
+
+		rss = enetc_rd(hw, ENETC_SIRSSCAPR);
+		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
 	}
+
+	if (val & ENETC_SIPCAPR0_QBV)
+		si->hw_features |= ENETC_SI_F_QBV;
 }
 
 static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
@@ -1314,8 +1319,12 @@ static void enetc_disable_interrupts(struct enetc_ndev_priv *priv)
 
 static void adjust_link(struct net_device *ndev)
 {
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct phy_device *phydev = ndev->phydev;
 
+	if (priv->active_offloads & ENETC_F_QBV)
+		enetc_sched_speed_set(ndev);
+
 	phy_print_status(phydev);
 }
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 8ca2f97050c8..89f23156f330 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -118,6 +118,8 @@ enum enetc_errata {
 	ENETC_ERR_UCMCSWP	= BIT(2),
 };
 
+#define ENETC_SI_F_QBV BIT(0)
+
 /* PCI IEP device data */
 struct enetc_si {
 	struct pci_dev *pdev;
@@ -133,6 +135,7 @@ struct enetc_si {
 	int num_fs_entries;
 	int num_rss; /* number of RSS buckets */
 	unsigned short pad;
+	int hw_features;
 };
 
 #define ENETC_SI_ALIGN	32
@@ -173,6 +176,7 @@ struct enetc_cls_rule {
 enum enetc_active_offloads {
 	ENETC_F_RX_TSTAMP	= BIT(0),
 	ENETC_F_TX_TSTAMP	= BIT(1),
+	ENETC_F_QBV             = BIT(2),
 };
 
 struct enetc_ndev_priv {
@@ -188,6 +192,8 @@ struct enetc_ndev_priv {
 	u16 msg_enable;
 	int active_offloads;
 
+	u32 speed; /* store speed for compare update pspeed */
+
 	struct enetc_bdr *tx_ring[16];
 	struct enetc_bdr *rx_ring[16];
 
@@ -248,6 +254,8 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
 
 #ifdef CONFIG_FSL_ENETC_QOS
 int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+void enetc_sched_speed_set(struct net_device *ndev);
 #else
 #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+#define enetc_sched_speed_set(ndev) (void)0
 #endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 7da79b816416..e7482d483b28 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -742,6 +742,9 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 
 	ndev->priv_flags |= IFF_UNICAST_FLT;
 
+	if (si->hw_features & ENETC_SI_F_QBV)
+		priv->active_offloads |= ENETC_F_QBV;
+
 	/* pick up primary MAC address from SI */
 	enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
 }
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index 036bb39c7a0b..801104dd2ba6 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -11,6 +11,40 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
 		& ENETC_QBV_MAX_GCL_LEN_MASK;
 }
 
+void enetc_sched_speed_set(struct net_device *ndev)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct phy_device *phydev = ndev->phydev;
+	u32 old_speed = priv->speed;
+	u32 speed, pspeed;
+
+	if (phydev->speed == old_speed)
+		return;
+
+	speed = phydev->speed;
+	switch (speed) {
+	case SPEED_1000:
+		pspeed = ENETC_PMR_PSPEED_1000M;
+		break;
+	case SPEED_2500:
+		pspeed = ENETC_PMR_PSPEED_2500M;
+		break;
+	case SPEED_100:
+		pspeed = ENETC_PMR_PSPEED_100M;
+		break;
+	case SPEED_10:
+	default:
+		pspeed = ENETC_PMR_PSPEED_10M;
+		netdev_err(ndev, "Qbv PSPEED set speed link down.\n");
+	}
+
+	priv->speed = speed;
+	enetc_port_wr(&priv->si->hw, ENETC_PMR,
+		      (enetc_port_rd(&priv->si->hw, ENETC_PMR)
+		      & (~ENETC_PMR_PSPEED_MASK))
+		      | pspeed);
+}
+
 static int enetc_setup_taprio(struct net_device *ndev,
 			      struct tc_taprio_qopt_offload *admin_conf)
 {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-11  4:41 ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
  2019-11-12  8:42   ` [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
@ 2019-11-12  9:41   ` Simon Horman
  2019-11-12 19:59   ` kbuild test robot
  2 siblings, 0 replies; 36+ messages in thread
From: Simon Horman @ 2019-11-12  9:41 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Mon, Nov 11, 2019 at 04:41:39AM +0000, Po Liu wrote:
> ENETC has a register PSPEED to indicate the link speed of hardware.
> It is need to update accordingly. PSPEED field needs to be updated
> with the port speed for QBV scheduling purposes. Or else there is
> chance for gate slot not free by frame taking the MAC if PSPEED and
> phy speed not match. So update PSPEED when link adjust. This is
> implement by the adjust_link.
> 
> Signed-off-by: Po Liu <Po.Liu@nxp.com>
> Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> Singed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
>  drivers/net/ethernet/freescale/enetc/enetc.c  | 13 +++++--
>  drivers/net/ethernet/freescale/enetc/enetc.h  |  7 ++++
>  .../net/ethernet/freescale/enetc/enetc_pf.c   |  3 ++
>  .../net/ethernet/freescale/enetc/enetc_qos.c  | 34 +++++++++++++++++++
>  4 files changed, 55 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
> index d58dbc2c4270..f6b00c68451b 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> @@ -742,9 +742,14 @@ void enetc_get_si_caps(struct enetc_si *si)
>  	si->num_rss = 0;
>  	val = enetc_rd(hw, ENETC_SIPCAPR0);
>  	if (val & ENETC_SIPCAPR0_RSS) {
> -		val = enetc_rd(hw, ENETC_SIRSSCAPR);
> -		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val);
> +		u32 rss;
> +
> +		rss = enetc_rd(hw, ENETC_SIRSSCAPR);
> +		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
>  	}
> +
> +	if (val & ENETC_SIPCAPR0_QBV)
> +		si->hw_features |= ENETC_SI_F_QBV;
>  }
>  
>  static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
> @@ -1314,8 +1319,12 @@ static void enetc_disable_interrupts(struct enetc_ndev_priv *priv)
>  
>  static void adjust_link(struct net_device *ndev)
>  {
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>  	struct phy_device *phydev = ndev->phydev;
>  
> +	if (priv->active_offloads & ENETC_F_QBV)
> +		enetc_sched_speed_set(ndev);
> +
>  	phy_print_status(phydev);
>  }
>  
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
> index 8676631041d5..e85e5301c578 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.h
> @@ -118,6 +118,8 @@ enum enetc_errata {
>  	ENETC_ERR_UCMCSWP	= BIT(2),
>  };
>  
> +#define ENETC_SI_F_QBV  (1<<0)
> +
>  /* PCI IEP device data */
>  struct enetc_si {
>  	struct pci_dev *pdev;
> @@ -133,6 +135,7 @@ struct enetc_si {
>  	int num_fs_entries;
>  	int num_rss; /* number of RSS buckets */
>  	unsigned short pad;
> +	int hw_features;
>  };
>  
>  #define ENETC_SI_ALIGN	32
> @@ -173,6 +176,7 @@ struct enetc_cls_rule {
>  enum enetc_active_offloads {
>  	ENETC_F_RX_TSTAMP	= BIT(0),
>  	ENETC_F_TX_TSTAMP	= BIT(1),
> +	ENETC_F_QBV             = BIT(2),
>  };
>  
>  struct enetc_ndev_priv {
> @@ -188,6 +192,8 @@ struct enetc_ndev_priv {
>  	u16 msg_enable;
>  	int active_offloads;
>  
> +	u32 speed; /* store speed for compare update pspeed */

struct phy_device seems to use int for speed.
Perhaps that would be a more appropriate type here,
and likewise in enetc_sched_speed_set().

> +
>  	struct enetc_bdr *tx_ring[16];
>  	struct enetc_bdr *rx_ring[16];
>  
> @@ -246,3 +252,4 @@ int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
>  int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
>  int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
>  int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
> +void enetc_sched_speed_set(struct net_device *ndev);
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> index 7da79b816416..e7482d483b28 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> @@ -742,6 +742,9 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
>  
>  	ndev->priv_flags |= IFF_UNICAST_FLT;
>  
> +	if (si->hw_features & ENETC_SI_F_QBV)
> +		priv->active_offloads |= ENETC_F_QBV;
> +
>  	/* pick up primary MAC address from SI */
>  	enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
>  }
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> index 036bb39c7a0b..801104dd2ba6 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> @@ -11,6 +11,40 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
>  		& ENETC_QBV_MAX_GCL_LEN_MASK;
>  }
>  
> +void enetc_sched_speed_set(struct net_device *ndev)
> +{
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +	struct phy_device *phydev = ndev->phydev;
> +	u32 old_speed = priv->speed;
> +	u32 speed, pspeed;
> +
> +	if (phydev->speed == old_speed)
> +		return;
> +
> +	speed = phydev->speed;
> +	switch (speed) {
> +	case SPEED_1000:
> +		pspeed = ENETC_PMR_PSPEED_1000M;
> +		break;
> +	case SPEED_2500:
> +		pspeed = ENETC_PMR_PSPEED_2500M;
> +		break;
> +	case SPEED_100:
> +		pspeed = ENETC_PMR_PSPEED_100M;
> +		break;
> +	case SPEED_10:
> +	default:
> +		pspeed = ENETC_PMR_PSPEED_10M;
> +		netdev_err(ndev, "Qbv PSPEED set speed link down.\n");
> +	}
> +
> +	priv->speed = speed;
> +	enetc_port_wr(&priv->si->hw, ENETC_PMR,
> +		      (enetc_port_rd(&priv->si->hw, ENETC_PMR)
> +		      & (~ENETC_PMR_PSPEED_MASK))
> +		      | pspeed);

The above two lines could be combined.

Also, the parentheses seem unnecessary.

> +}
> +
>  static int enetc_setup_taprio(struct net_device *ndev,
>  			      struct tc_taprio_qopt_offload *admin_conf)
>  {
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-11  4:41 ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
  2019-11-12  5:50 ` [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload David Miller
@ 2019-11-12  9:41 ` Simon Horman
  2019-11-12 11:19   ` [EXT] " Po Liu
  2019-11-12 18:58   ` David Miller
  2019-11-12 12:31 ` kbuild test robot
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 36+ messages in thread
From: Simon Horman @ 2019-11-12  9:41 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Mon, Nov 11, 2019 at 04:41:26AM +0000, Po Liu wrote:
> ENETC supports in hardware for time-based egress shaping according
> to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
> hardware offload method qdisc tc-taprio method.
> Also update cbdr writeback to up level since control bd ring may
> writeback data to control bd ring.
> 
> Signed-off-by: Po Liu <Po.Liu@nxp.com>
> Singed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> ---
>  drivers/net/ethernet/freescale/enetc/Makefile |   1 +
>  drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
>  drivers/net/ethernet/freescale/enetc/enetc.h  |   2 +
>  .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
>  .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
>  .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
>  6 files changed, 285 insertions(+), 22 deletions(-)
>  create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
> 
> diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
> index d200c27c3bf6..389f722efc43 100644
> --- a/drivers/net/ethernet/freescale/enetc/Makefile
> +++ b/drivers/net/ethernet/freescale/enetc/Makefile
> @@ -5,6 +5,7 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
>  obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
>  fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
>  fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
> +fsl-enetc-$(CONFIG_NET_SCH_TAPRIO) += enetc_qos.o
>  
>  obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
>  fsl-enetc-vf-y := enetc_vf.o $(common-objs)
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
> index 3e8f9819f08c..d58dbc2c4270 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> @@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
>  	return 0;
>  }
>  
> -int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> -		   void *type_data)
> +int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
>  {
>  	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>  	struct tc_mqprio_qopt *mqprio = type_data;
> @@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>  	u8 num_tc;
>  	int i;
>  
> -	if (type != TC_SETUP_QDISC_MQPRIO)
> -		return -EOPNOTSUPP;
> -
>  	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
>  	num_tc = mqprio->num_tc;
>  
> @@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>  	return 0;
>  }
>  
> +int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> +		   void *type_data)
> +{
> +	switch (type) {
> +	case TC_SETUP_QDISC_MQPRIO:
> +		return enetc_setup_tc_mqprio(ndev, type_data);
> +	case TC_SETUP_QDISC_TAPRIO:
> +		return enetc_setup_tc_taprio(ndev, type_data);
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
>  struct net_device_stats *enetc_get_stats(struct net_device *ndev)
>  {
>  	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
> index 541b4e2073fe..8676631041d5 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.h
> @@ -244,3 +244,5 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
>  void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
>  int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
>  int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
> +int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
> +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> index de466b71bf8f..201cbc362e33 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> @@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
>  		r->bd_count;
>  }
>  
> -static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> +int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
>  {
>  	struct enetc_cbdr *ring = &si->cbd_ring;
>  	int timeout = ENETC_CBDR_TIMEOUT;
> @@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
>  	if (!timeout)
>  		return -EBUSY;
>  
> +	/* CBD may writeback data, feedback up level */
> +	*cbd = *dest_cbd;
> +
>  	enetc_clean_cbdr(si);
>  
>  	return 0;
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> index 88276299f447..75a7c0f1f8ce 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> @@ -18,6 +18,7 @@
>  #define ENETC_SICTR0	0x18
>  #define ENETC_SICTR1	0x1c
>  #define ENETC_SIPCAPR0	0x20
> +#define ENETC_SIPCAPR0_QBV	BIT(4)
>  #define ENETC_SIPCAPR0_RSS	BIT(8)
>  #define ENETC_SIPCAPR1	0x24
>  #define ENETC_SITGTGR	0x30
> @@ -148,6 +149,12 @@ enum enetc_bdr_type {TX, RX};
>  #define ENETC_PORT_BASE		0x10000
>  #define ENETC_PMR		0x0000
>  #define ENETC_PMR_EN	GENMASK(18, 16)
> +#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
> +#define ENETC_PMR_PSPEED_10M 0x000
> +#define ENETC_PMR_PSPEED_100M 0x100
> +#define ENETC_PMR_PSPEED_1000M 0x200
> +#define ENETC_PMR_PSPEED_2500M 0x400

Perhaps BIT() is appropriate here.

The changes above to enetc_hw.h are not used until the following patch,
perhaps it would be better if they were part of that patch.

> +
>  #define ENETC_PSR		0x0004 /* RO */
>  #define ENETC_PSIPMR		0x0018
>  #define ENETC_PSIPMR_SET_UP(n)	BIT(n) /* n = SI index */
> @@ -440,22 +447,6 @@ union enetc_rx_bd {
>  #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
>  #define ENETC_MAX_NUM_VFS	2
>  
> -struct enetc_cbd {
> -	union {
> -		struct {
> -			__le32 addr[2];
> -			__le32 opt[4];
> -		};
> -		__le32 data[6];
> -	};
> -	__le16 index;
> -	__le16 length;
> -	u8 cmd;
> -	u8 cls;
> -	u8 _res;
> -	u8 status_flags;
> -};
> -
>  #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
>  #define ENETC_CBD_STATUS_MASK	0xf
>  
> @@ -554,3 +545,130 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
>  	val |= ENETC_TBMR_SET_PRIO(prio);
>  	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
>  }
> +
> +enum bdcr_cmd_class {
> +	BDCR_CMD_UNSPEC = 0,
> +	BDCR_CMD_MAC_FILTER,
> +	BDCR_CMD_VLAN_FILTER,
> +	BDCR_CMD_RSS,
> +	BDCR_CMD_RFS,
> +	BDCR_CMD_PORT_GCL,
> +	BDCR_CMD_RECV_CLASSIFIER,
> +	__BDCR_CMD_MAX_LEN,
> +	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
> +};
> +
> +/* class 5, command 0 */
> +struct tgs_gcl_conf {
> +	u8	atc;	/* init gate value */
> +	u8	res[7];
> +	union {
> +		struct {
> +			u8	res1[4];
> +			__le16	acl_len;

Given that u* types are used in this structure I think le16 would
be more appropriate than __le16.

> +			u8	res2[2];
> +		};
> +		struct {
> +			u32 cctl;
> +			u32 ccth;
> +		};

I'm a little surprised to see host endian values in a structure
that appears to be written to hardware. Is this intentional?

Also, these fields do not seem to be used in this patch-set.
Is that also intentional?

> +	};
> +};
> +
> +#define ENETC_CBDR_SGL_IOMEN	BIT(0)
> +#define ENETC_CBDR_SGL_IPVEN	BIT(3)
> +#define ENETC_CBDR_SGL_GTST	BIT(4)
> +#define ENETC_CBDR_SGL_IPV_MASK 0xe

Perhaps GENMASK() is appropriate here and elsewhere for generating masks.

> +
> +/* gate control list entry */
> +struct gce {
> +	u32	period;

Likewise, I'm a little surprised to see host-byte order data to
be written to HW. And below too. Though as I've noted below,
some of these values are used to store le32 data, so it seems
that the types are incorrect.

> +	u8	gate;
> +	u8	res[3];
> +};
> +
> +/* tgs_gcl_conf address point to this data space */
> +struct tgs_gcl_data {
> +	u32	btl;
> +	u32	bth;
> +	u32	ct;
> +	u32	cte;
> +};
> +
> +/* class 5, command 1 */
> +struct tgs_gcl_query {
> +		u8	res[12];
> +		union {
> +			struct {
> +				__le16	acl_len; /* admin list length */
> +				__le16	ocl_len; /* operation list length */
> +			};
> +			struct {
> +				u16 admin_list_len;
> +				u16 oper_list_len;

	Again, is it intentional that these are a) host-byte order and
	b) unused?

> +			};
> +		};
> +};
> +
> +/* tgs_gcl_query command response data format */
> +struct tgs_gcl_resp {
> +	u32 abtl;	/* base time */
> +	u32 abth;
> +	u32 act;	/* cycle time */
> +	u32 acte;	/* cycle time extend */
> +	u32 cctl;	/* config change time */
> +	u32 ccth;
> +	u32 obtl;	/* operation base time */
> +	u32 obth;
> +	u32 oct;	/* operation cycle time */
> +	u32 octe;	/* operation cycle time extend */
> +	u32 ccel;	/* config change error */
> +	u32 cceh;
> +};

This structure seems unused in this patchset.

> +
> +struct enetc_cbd {
> +	union{
> +		struct {
> +			__le32	addr[2];
> +			union {
> +				__le32	opt[4];
> +				struct tgs_gcl_conf	gcl_conf;
> +				struct tgs_gcl_query	gcl_query;
> +			};
> +		};	/* Long format */
> +		__le32 data[6];
> +	};
> +	__le16 index;
> +	__le16 length;
> +	u8 cmd;
> +	u8 cls;
> +	u8 _res;
> +	u8 status_flags;
> +};
> +
> +#define ENETC_PTCFPR(n)		(0x1910 + (n) * 4) /* n = [0 ..7] */
> +#define ENETC_FPE		BIT(31)
> +
> +/* Port capability register 0 */
> +#define ENETC_PCAPR0_PSFPM	BIT(10)
> +#define ENETC_PCAPR0_PSFP	BIT(9)
> +#define ENETC_PCAPR0_TSN	BIT(4)
> +#define ENETC_PCAPR0_QBU	BIT(3)
> +
> +/* port time gating control register */
> +#define ENETC_QBV_PTGCR_OFFSET		0x11a00
> +#define ENETC_QBV_TGE			0x80000000
> +#define ENETC_QBV_TGPE			BIT(30)
> +#define ENETC_QBV_TGDROP_DISABLE	BIT(29)
> +
> +/* Port time gating capability register */
> +#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
> +#define ENETC_QBV_MAX_GCL_LEN_MASK	0xffff
> +
> +/* Port time gating admin gate list status register */
> +#define ENETC_QBV_PTGAGLSR_OFFSET	0x11a10
> +#define ENETC_QBV_CFG_PEND_MASK	0x00000002
> +
> +#define ENETC_TGLSTR			0xa200
> +#define ENETC_TGS_MIN_DIS_MASK		0x80000000
> +#define ENETC_MIN_LOOKAHEAD_MASK	0xffff
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> new file mode 100644
> index 000000000000..036bb39c7a0b
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> @@ -0,0 +1,130 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
> +/* Copyright 2019 NXP */
> +
> +#include "enetc.h"
> +
> +#include <net/pkt_sched.h>
> +
> +static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
> +{
> +	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
> +		& ENETC_QBV_MAX_GCL_LEN_MASK;
> +}
> +
> +static int enetc_setup_taprio(struct net_device *ndev,
> +			      struct tc_taprio_qopt_offload *admin_conf)
> +{
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +	struct enetc_cbd cbd = {.cmd = 0};
> +	struct tgs_gcl_conf *gcl_config;
> +	struct tgs_gcl_data *gcl_data;
> +	struct gce *gce;
> +	dma_addr_t dma;
> +	u16 data_size;
> +	u16 gcl_len;
> +	u32 temp;
> +	int i;
> +
> +	gcl_len = admin_conf->num_entries;
> +	if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
> +		return -EINVAL;
> +
> +	if (admin_conf->enable) {
> +		enetc_wr(&priv->si->hw,
> +			 ENETC_QBV_PTGCR_OFFSET,
> +			 temp & (~ENETC_QBV_TGE));

The enetc_wr() call seems to be common to both arms of the condition.
If so perhaps it could be move outside of the condition.

> +		usleep_range(10, 20);
> +		enetc_wr(&priv->si->hw,
> +			 ENETC_QBV_PTGCR_OFFSET,
> +			 temp | ENETC_QBV_TGE);
> +	} else {
> +		enetc_wr(&priv->si->hw,
> +			 ENETC_QBV_PTGCR_OFFSET,
> +			 temp & (~ENETC_QBV_TGE));
> +		return 0;
> +	}
> +
> +	/* Configure the (administrative) gate control list using the
> +	 * control BD descriptor.
> +	 */
> +	gcl_config = &cbd.gcl_conf;
> +
> +	data_size = sizeof(struct tgs_gcl_data) + gcl_len * sizeof(struct gce);

I think struct_size() can be used here.

> +
> +	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
> +	if (!gcl_data)
> +		return -ENOMEM;
> +
> +	gce = (struct gce *)(gcl_data + 1);
> +
> +	/* Since no initial state config in taprio, set gates open as default.
> +	 */
> +	gcl_config->atc = 0xff;
> +	gcl_config->acl_len = cpu_to_le16(gcl_len);
> +
> +	if (!admin_conf->base_time) {
> +		gcl_data->btl =
> +			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
> +		gcl_data->bth =
> +			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
> +	} else {
> +		gcl_data->btl =
> +			cpu_to_le32(lower_32_bits(admin_conf->base_time));
> +		gcl_data->bth =
> +			cpu_to_le32(upper_32_bits(admin_conf->base_time));
> +	}

It looks like the types of the btl and bth fields are u32.
Perhaps they should be le32?

Please consider running sparse over this code to check for any endian
problems.

> +
> +	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
> +	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
> +
> +	for (i = 0; i < gcl_len; i++) {
> +		struct tc_taprio_sched_entry *temp_entry;
> +		struct gce *temp_gce = gce + i;
> +
> +		temp_entry = &admin_conf->entries[i];
> +
> +		temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);

	Gate is a u8 followed by 3 reserved bytes.
	Perhaps there needs to be some bounds checking on
	the value stored there given that the source is 32bits wide.

	Also, its not clear to me that the above logic, which I assume
	takes the last significant byte of a 32bit value, works on
	big endian systems as the 32bit value is always little endian.

> +		temp_gce->period = cpu_to_le32(temp_entry->interval);

	It looks like the types of the gate field is u32.
	Perhaps it should be le32?

> +	}
> +
> +	cbd.length = cpu_to_le16(data_size);
> +	cbd.status_flags = 0;
> +
> +	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
> +			     data_size, DMA_TO_DEVICE);
> +	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
> +		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
> +		kfree(gcl_data);
> +		return -ENOMEM;
> +	}
> +
> +	cbd.addr[0] = lower_32_bits(dma);
> +	cbd.addr[1] = upper_32_bits(dma);
> +	cbd.cls = BDCR_CMD_PORT_GCL;
> +
> +	/* Updated by ENETC on completion of the configuration
> +	 * command. A zero value indicates success.
> +	 */
> +	cbd.status_flags = 0;
> +
> +	enetc_send_cmd(priv->si, &cbd);
> +
> +	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
> +	kfree(gcl_data);
> +
> +	return 0;
> +}
> +
> +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
> +{
> +	struct tc_taprio_qopt_offload *taprio = type_data;
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +	int i;
> +
> +	for (i = 0; i < priv->num_tx_rings; i++)
> +		enetc_set_bdr_prio(&priv->si->hw,
> +				   priv->tx_ring[i]->index,
> +				   taprio->enable ? i : 0);
> +
> +	return enetc_setup_taprio(ndev, taprio);
> +}
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12  9:41 ` Simon Horman
@ 2019-11-12 11:19   ` Po Liu
  2019-11-12 11:54     ` Claudiu Manoil
  2019-11-12 13:50     ` Simon Horman
  2019-11-12 18:58   ` David Miller
  1 sibling, 2 replies; 36+ messages in thread
From: Po Liu @ 2019-11-12 11:19 UTC (permalink / raw)
  To: Simon Horman
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li




Br,
Po Liu

> -----Original Message-----
> From: Simon Horman <simon.horman@netronome.com>
> Sent: 2019年11月12日 17:41
> To: Po Liu <po.liu@nxp.com>
> Cc: Claudiu Manoil <claudiu.manoil@nxp.com>; davem@davemloft.net; linux-
> kernel@vger.kernel.org; netdev@vger.kernel.org; vinicius.gomes@intel.com;
> Vladimir Oltean <vladimir.oltean@nxp.com>; Alexandru Marginean
> <alexandru.marginean@nxp.com>; Xiaoliang Yang
> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
> <leoyang.li@nxp.com>
> Subject: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via
> tc-taprio offload
> 
> Caution: EXT Email
> 
> On Mon, Nov 11, 2019 at 04:41:26AM +0000, Po Liu wrote:
> > ENETC supports in hardware for time-based egress shaping according to
> > IEEE 802.1Qbv. This patch implement the Qbv enablement by the hardware
> > offload method qdisc tc-taprio method.
> > Also update cbdr writeback to up level since control bd ring may
> > writeback data to control bd ring.
> >
> > Signed-off-by: Po Liu <Po.Liu@nxp.com>
> > Singed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> > Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> > ---
> >  drivers/net/ethernet/freescale/enetc/Makefile |   1 +
> >  drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> >  drivers/net/ethernet/freescale/enetc/enetc.h  |   2 +
> >  .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> >  .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
> >  .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
> >  6 files changed, 285 insertions(+), 22 deletions(-)  create mode
> > 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >
> > diff --git a/drivers/net/ethernet/freescale/enetc/Makefile
> > b/drivers/net/ethernet/freescale/enetc/Makefile
> > index d200c27c3bf6..389f722efc43 100644
> > --- a/drivers/net/ethernet/freescale/enetc/Makefile
> > +++ b/drivers/net/ethernet/freescale/enetc/Makefile
> > @@ -5,6 +5,7 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
> >  obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o  fsl-enetc-y := enetc_pf.o
> > enetc_mdio.o $(common-objs)
> >  fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
> > +fsl-enetc-$(CONFIG_NET_SCH_TAPRIO) += enetc_qos.o
> >
> >  obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o  fsl-enetc-vf-y :=
> > enetc_vf.o $(common-objs) diff --git
> > a/drivers/net/ethernet/freescale/enetc/enetc.c
> > b/drivers/net/ethernet/freescale/enetc/enetc.c
> > index 3e8f9819f08c..d58dbc2c4270 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> > @@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
> >       return 0;
> >  }
> >
> > -int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> > -                void *type_data)
> > +int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
> >  {
> >       struct enetc_ndev_priv *priv = netdev_priv(ndev);
> >       struct tc_mqprio_qopt *mqprio = type_data; @@ -1436,9 +1435,6 @@
> > int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> >       u8 num_tc;
> >       int i;
> >
> > -     if (type != TC_SETUP_QDISC_MQPRIO)
> > -             return -EOPNOTSUPP;
> > -
> >       mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
> >       num_tc = mqprio->num_tc;
> >
> > @@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev,
> enum tc_setup_type type,
> >       return 0;
> >  }
> >
> > +int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> > +                void *type_data)
> > +{
> > +     switch (type) {
> > +     case TC_SETUP_QDISC_MQPRIO:
> > +             return enetc_setup_tc_mqprio(ndev, type_data);
> > +     case TC_SETUP_QDISC_TAPRIO:
> > +             return enetc_setup_tc_taprio(ndev, type_data);
> > +     default:
> > +             return -EOPNOTSUPP;
> > +     }
> > +}
> > +
> >  struct net_device_stats *enetc_get_stats(struct net_device *ndev)  {
> >       struct enetc_ndev_priv *priv = netdev_priv(ndev); diff --git
> > a/drivers/net/ethernet/freescale/enetc/enetc.h
> > b/drivers/net/ethernet/freescale/enetc/enetc.h
> > index 541b4e2073fe..8676631041d5 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc.h
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc.h
> > @@ -244,3 +244,5 @@ int enetc_set_fs_entry(struct enetc_si *si, struct
> > enetc_cmd_rfse *rfse,  void enetc_set_rss_key(struct enetc_hw *hw,
> > const u8 *bytes);  int enetc_get_rss_table(struct enetc_si *si, u32
> > *table, int count);  int enetc_set_rss_table(struct enetc_si *si,
> > const u32 *table, int count);
> > +int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd); int
> > +enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> > b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> > index de466b71bf8f..201cbc362e33 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> > @@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
> >               r->bd_count;
> >  }
> >
> > -static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> > +int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> >  {
> >       struct enetc_cbdr *ring = &si->cbd_ring;
> >       int timeout = ENETC_CBDR_TIMEOUT; @@ -66,6 +66,9 @@ static int
> > enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> >       if (!timeout)
> >               return -EBUSY;
> >
> > +     /* CBD may writeback data, feedback up level */
> > +     *cbd = *dest_cbd;
> > +
> >       enetc_clean_cbdr(si);
> >
> >       return 0;
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> > b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> > index 88276299f447..75a7c0f1f8ce 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> > @@ -18,6 +18,7 @@
> >  #define ENETC_SICTR0 0x18
> >  #define ENETC_SICTR1 0x1c
> >  #define ENETC_SIPCAPR0       0x20
> > +#define ENETC_SIPCAPR0_QBV   BIT(4)
> >  #define ENETC_SIPCAPR0_RSS   BIT(8)
> >  #define ENETC_SIPCAPR1       0x24
> >  #define ENETC_SITGTGR        0x30
> > @@ -148,6 +149,12 @@ enum enetc_bdr_type {TX, RX};
> >  #define ENETC_PORT_BASE              0x10000
> >  #define ENETC_PMR            0x0000
> >  #define ENETC_PMR_EN GENMASK(18, 16)
> > +#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8) #define
> > +ENETC_PMR_PSPEED_10M 0x000 #define ENETC_PMR_PSPEED_100M
> 0x100
> > +#define ENETC_PMR_PSPEED_1000M 0x200 #define
> ENETC_PMR_PSPEED_2500M
> > +0x400
> 
> Perhaps BIT() is appropriate here.

Will change to BIT().

> 
> The changes above to enetc_hw.h are not used until the following patch,
> perhaps it would be better if they were part of that patch.
>
Yes, better to move to patch 2/2.

> > +
> >  #define ENETC_PSR            0x0004 /* RO */
> >  #define ENETC_PSIPMR         0x0018
> >  #define ENETC_PSIPMR_SET_UP(n)       BIT(n) /* n = SI index */
> > @@ -440,22 +447,6 @@ union enetc_rx_bd {
> >  #define EMETC_MAC_ADDR_FILT_RES      3 /* # of reserved entries at the
> beginning */
> >  #define ENETC_MAX_NUM_VFS    2
> >
> > -struct enetc_cbd {
> > -     union {
> > -             struct {
> > -                     __le32 addr[2];
> > -                     __le32 opt[4];
> > -             };
> > -             __le32 data[6];
> > -     };
> > -     __le16 index;
> > -     __le16 length;
> > -     u8 cmd;
> > -     u8 cls;
> > -     u8 _res;
> > -     u8 status_flags;
> > -};
> > -
> >  #define ENETC_CBD_FLAGS_SF   BIT(7) /* short format */
> >  #define ENETC_CBD_STATUS_MASK        0xf
> >
> > @@ -554,3 +545,130 @@ static inline void enetc_set_bdr_prio(struct
> enetc_hw *hw, int bdr_idx,
> >       val |= ENETC_TBMR_SET_PRIO(prio);
> >       enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);  }
> > +
> > +enum bdcr_cmd_class {
> > +     BDCR_CMD_UNSPEC = 0,
> > +     BDCR_CMD_MAC_FILTER,
> > +     BDCR_CMD_VLAN_FILTER,
> > +     BDCR_CMD_RSS,
> > +     BDCR_CMD_RFS,
> > +     BDCR_CMD_PORT_GCL,
> > +     BDCR_CMD_RECV_CLASSIFIER,
> > +     __BDCR_CMD_MAX_LEN,
> > +     BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1, };
> > +
> > +/* class 5, command 0 */
> > +struct tgs_gcl_conf {
> > +     u8      atc;    /* init gate value */
> > +     u8      res[7];
> > +     union {
> > +             struct {
> > +                     u8      res1[4];
> > +                     __le16  acl_len;
> 
> Given that u* types are used in this structure I think le16 would be more
> appropriate than __le16.
 
Here keep the same code style of this .h file. I think it is better to have another patch to fix them all. Do you agree?

> 
> > +                     u8      res2[2];
> > +             };
> > +             struct {
> > +                     u32 cctl;
> > +                     u32 ccth;
> > +             };
> 
> I'm a little surprised to see host endian values in a structure that appears to be
> written to hardware. Is this intentional?

Will remove.

> 
> Also, these fields do not seem to be used in this patch-set.
> Is that also intentional?

This is defined hardware writeback value, can be remove temporary.

> 
> > +     };
> > +};
> > +
> > +#define ENETC_CBDR_SGL_IOMEN BIT(0)
> > +#define ENETC_CBDR_SGL_IPVEN BIT(3)
> > +#define ENETC_CBDR_SGL_GTST  BIT(4)
> > +#define ENETC_CBDR_SGL_IPV_MASK 0xe
> 
> Perhaps GENMASK() is appropriate here and elsewhere for generating masks.
> 

Will remove these define in this patch.

> > +
> > +/* gate control list entry */
> > +struct gce {
> > +     u32     period;
> 
> Likewise, I'm a little surprised to see host-byte order data to be written to HW.
> And below too. Though as I've noted below, some of these values are used to
> store le32 data, so it seems that the types are incorrect

Ok.  change to le32.

> 
> > +     u8      gate;
> > +     u8      res[3];
> > +};
> > +
> > +/* tgs_gcl_conf address point to this data space */ struct
> > +tgs_gcl_data {
> > +     u32     btl;
> > +     u32     bth;
> > +     u32     ct;
> > +     u32     cte;
> > +};
> > +

Ok. change to le32.

> > +/* class 5, command 1 */
> > +struct tgs_gcl_query {
> > +             u8      res[12];
> > +             union {
> > +                     struct {
> > +                             __le16  acl_len; /* admin list length */
> > +                             __le16  ocl_len; /* operation list length */
> > +                     };
> > +                     struct {
> > +                             u16 admin_list_len;
> > +                             u16 oper_list_len;
> 
>         Again, is it intentional that these are a) host-byte order and
>         b) unused?

Ok. Can be remove temporary.

> 
> > +                     };
> > +             };
> > +};
> > +
> > +/* tgs_gcl_query command response data format */ struct tgs_gcl_resp
> > +{
> > +     u32 abtl;       /* base time */
> > +     u32 abth;
> > +     u32 act;        /* cycle time */
> > +     u32 acte;       /* cycle time extend */
> > +     u32 cctl;       /* config change time */
> > +     u32 ccth;
> > +     u32 obtl;       /* operation base time */
> > +     u32 obth;
> > +     u32 oct;        /* operation cycle time */
> > +     u32 octe;       /* operation cycle time extend */
> > +     u32 ccel;       /* config change error */
> > +     u32 cceh;
> > +};
> 
> This structure seems unused in this patchset.

Will remove.

> 
> > +
> > +struct enetc_cbd {
> > +     union{
> > +             struct {
> > +                     __le32  addr[2];
> > +                     union {
> > +                             __le32  opt[4];
> > +                             struct tgs_gcl_conf     gcl_conf;
> > +                             struct tgs_gcl_query    gcl_query;
> > +                     };
> > +             };      /* Long format */
> > +             __le32 data[6];
> > +     };
> > +     __le16 index;
> > +     __le16 length;
> > +     u8 cmd;
> > +     u8 cls;
> > +     u8 _res;
> > +     u8 status_flags;
> > +};
> > +
> > +#define ENETC_PTCFPR(n)              (0x1910 + (n) * 4) /* n = [0 ..7] */
> > +#define ENETC_FPE            BIT(31)
> > +
> > +/* Port capability register 0 */
> > +#define ENETC_PCAPR0_PSFPM   BIT(10)
> > +#define ENETC_PCAPR0_PSFP    BIT(9)
> > +#define ENETC_PCAPR0_TSN     BIT(4)
> > +#define ENETC_PCAPR0_QBU     BIT(3)
> > +
> > +/* port time gating control register */
> > +#define ENETC_QBV_PTGCR_OFFSET               0x11a00
> > +#define ENETC_QBV_TGE                        0x80000000
> > +#define ENETC_QBV_TGPE                       BIT(30)
> > +#define ENETC_QBV_TGDROP_DISABLE     BIT(29)
> > +
> > +/* Port time gating capability register */
> > +#define ENETC_QBV_PTGCAPR_OFFSET     0x11a08
> > +#define ENETC_QBV_MAX_GCL_LEN_MASK   0xffff
> > +
> > +/* Port time gating admin gate list status register */
> > +#define ENETC_QBV_PTGAGLSR_OFFSET    0x11a10
> > +#define ENETC_QBV_CFG_PEND_MASK      0x00000002
> > +
> > +#define ENETC_TGLSTR                 0xa200
> > +#define ENETC_TGS_MIN_DIS_MASK               0x80000000
> > +#define ENETC_MIN_LOOKAHEAD_MASK     0xffff
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> > b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> > new file mode 100644
> > index 000000000000..036bb39c7a0b
> > --- /dev/null
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> > @@ -0,0 +1,130 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
> > +/* Copyright 2019 NXP */
> > +
> > +#include "enetc.h"
> > +
> > +#include <net/pkt_sched.h>
> > +
> > +static u16 enetc_get_max_gcl_len(struct enetc_hw *hw) {
> > +     return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
> > +             & ENETC_QBV_MAX_GCL_LEN_MASK; }
> > +
> > +static int enetc_setup_taprio(struct net_device *ndev,
> > +                           struct tc_taprio_qopt_offload *admin_conf)
> > +{
> > +     struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > +     struct enetc_cbd cbd = {.cmd = 0};
> > +     struct tgs_gcl_conf *gcl_config;
> > +     struct tgs_gcl_data *gcl_data;
> > +     struct gce *gce;
> > +     dma_addr_t dma;
> > +     u16 data_size;
> > +     u16 gcl_len;
> > +     u32 temp;
> > +     int i;
> > +
> > +     gcl_len = admin_conf->num_entries;
> > +     if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
> > +             return -EINVAL;
> > +
> > +     if (admin_conf->enable) {
> > +             enetc_wr(&priv->si->hw,
> > +                      ENETC_QBV_PTGCR_OFFSET,
> > +                      temp & (~ENETC_QBV_TGE));
> 
> The enetc_wr() call seems to be common to both arms of the condition.
> If so perhaps it could be move outside of the condition.

Ok. will move it down after the if condition.

> 
> > +             usleep_range(10, 20);
> > +             enetc_wr(&priv->si->hw,
> > +                      ENETC_QBV_PTGCR_OFFSET,
> > +                      temp | ENETC_QBV_TGE);
> > +     } else {
> > +             enetc_wr(&priv->si->hw,
> > +                      ENETC_QBV_PTGCR_OFFSET,
> > +                      temp & (~ENETC_QBV_TGE));
> > +             return 0;
> > +     }
> > +
> > +     /* Configure the (administrative) gate control list using the
> > +      * control BD descriptor.
> > +      */
> > +     gcl_config = &cbd.gcl_conf;
> > +
> > +     data_size = sizeof(struct tgs_gcl_data) + gcl_len *
> > + sizeof(struct gce);
> 
> I think struct_size() can be used here.

Ok.

> 
> > +
> > +     gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
> > +     if (!gcl_data)
> > +             return -ENOMEM;
> > +
> > +     gce = (struct gce *)(gcl_data + 1);
> > +
> > +     /* Since no initial state config in taprio, set gates open as default.
> > +      */
> > +     gcl_config->atc = 0xff;
> > +     gcl_config->acl_len = cpu_to_le16(gcl_len);
> > +
> > +     if (!admin_conf->base_time) {
> > +             gcl_data->btl =
> > +                     cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
> > +             gcl_data->bth =
> > +                     cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
> > +     } else {
> > +             gcl_data->btl =
> > +                     cpu_to_le32(lower_32_bits(admin_conf->base_time));
> > +             gcl_data->bth =
> > +                     cpu_to_le32(upper_32_bits(admin_conf->base_time));
> > +     }
> 
> It looks like the types of the btl and bth fields are u32.
> Perhaps they should be le32?

Ok. should be le32.

> 
> Please consider running sparse over this code to check for any endian problems.
> 
> > +
> > +     gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
> > +     gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
> > +
> > +     for (i = 0; i < gcl_len; i++) {
> > +             struct tc_taprio_sched_entry *temp_entry;
> > +             struct gce *temp_gce = gce + i;
> > +
> > +             temp_entry = &admin_conf->entries[i];
> > +
> > +             temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);
> 
>         Gate is a u8 followed by 3 reserved bytes.
>         Perhaps there needs to be some bounds checking on
>         the value stored there given that the source is 32bits wide.
> 
>         Also, its not clear to me that the above logic, which I assume
>         takes the last significant byte of a 32bit value, works on
>         big endian systems as the 32bit value is always little endian.

temp_entry->gate_mask is 32bit for wide possible input. Here change to hardware set 8bit wide.
Can it just be like:
	temp_gce->gate = (u8) temp_entry->gate_mask;

> 
> > +             temp_gce->period = cpu_to_le32(temp_entry->interval);
> 
>         It looks like the types of the gate field is u32.
>         Perhaps it should be le32?

Ok. should be le32.

> 
> > +     }
> > +
> > +     cbd.length = cpu_to_le16(data_size);
> > +     cbd.status_flags = 0;
> > +
> > +     dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
> > +                          data_size, DMA_TO_DEVICE);
> > +     if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
> > +             netdev_err(priv->si->ndev, "DMA mapping failed!\n");
> > +             kfree(gcl_data);
> > +             return -ENOMEM;
> > +     }
> > +
> > +     cbd.addr[0] = lower_32_bits(dma);
> > +     cbd.addr[1] = upper_32_bits(dma);
> > +     cbd.cls = BDCR_CMD_PORT_GCL;
> > +
> > +     /* Updated by ENETC on completion of the configuration
> > +      * command. A zero value indicates success.
> > +      */
> > +     cbd.status_flags = 0;
> > +
> > +     enetc_send_cmd(priv->si, &cbd);
> > +
> > +     dma_unmap_single(&priv->si->pdev->dev, dma, data_size,
> DMA_TO_DEVICE);
> > +     kfree(gcl_data);
> > +
> > +     return 0;
> > +}
> > +
> > +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) {
> > +     struct tc_taprio_qopt_offload *taprio = type_data;
> > +     struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > +     int i;
> > +
> > +     for (i = 0; i < priv->num_tx_rings; i++)
> > +             enetc_set_bdr_prio(&priv->si->hw,
> > +                                priv->tx_ring[i]->index,
> > +                                taprio->enable ? i : 0);
> > +
> > +     return enetc_setup_taprio(ndev, taprio); }
> > --
> > 2.17.1
> >

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12 11:19   ` [EXT] " Po Liu
@ 2019-11-12 11:54     ` Claudiu Manoil
  2019-11-12 13:46       ` Simon Horman
  2019-11-12 13:50     ` Simon Horman
  1 sibling, 1 reply; 36+ messages in thread
From: Claudiu Manoil @ 2019-11-12 11:54 UTC (permalink / raw)
  To: Po Liu, Simon Horman
  Cc: davem, linux-kernel, netdev, vinicius.gomes, Vladimir Oltean,
	Alexandru Marginean, Xiaoliang Yang, Roy Zang, Mingkai Hu,
	Jerry Huang, Leo Li

>-----Original Message-----
>From: Po Liu <po.liu@nxp.com>
[...]
>> -----Original Message-----
>> From: Simon Horman <simon.horman@netronome.com>
[...]
>> > +/* class 5, command 0 */
>> > +struct tgs_gcl_conf {
>> > +     u8      atc;    /* init gate value */
>> > +     u8      res[7];
>> > +     union {
>> > +             struct {
>> > +                     u8      res1[4];
>> > +                     __le16  acl_len;
>>
>> Given that u* types are used in this structure I think le16 would be more
>> appropriate than __le16.
>
>Here keep the same code style of this .h file. I think it is better to have
>another patch to fix them all. Do you agree?
>

I don't see why "le16" would be more appropriate than "__le16" in this context.
The "__leXX" types are widely used in kernel drivers and not only, to annotate the
endianess of the hardware.  These are generic types defined din "include/uapi/linux/types.h".
Whereas "leXX" are defined in "fs/ntfs/types.h", and there's no usage of these types
in other h/w device drivers (I didn't find any).  Am I missing anything?

-Claudiu

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
                   ` (2 preceding siblings ...)
  2019-11-12  9:41 ` Simon Horman
@ 2019-11-12 12:31 ` kbuild test robot
  2019-11-12 12:43 ` kbuild test robot
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2019-11-12 12:31 UTC (permalink / raw)
  To: Po Liu
  Cc: kbuild-all, Claudiu Manoil, davem, linux-kernel, netdev,
	vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li

[-- Attachment #1: Type: text/plain, Size: 3692 bytes --]

Hi Po,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]
[also build test WARNING on v5.4-rc7 next-20191111]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Po-Liu/enetc-Configure-the-Time-Aware-Scheduler-via-tc-taprio-offload/20191112-193235
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git ca22d6977b9b4ab0fd2e7909b57e32ba5b95046f
config: s390-allmodconfig (attached as .config)
compiler: s390-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=s390 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   In file included from arch/s390/include/asm/io.h:76:0,
                    from include/linux/io.h:13,
                    from include/linux/pci.h:39,
                    from drivers/net/ethernet/freescale/enetc/enetc.h:5,
                    from drivers/net/ethernet/freescale/enetc/enetc_qos.c:4:
   drivers/net/ethernet/freescale/enetc/enetc_qos.c: In function 'enetc_setup_tc_taprio':
>> include/asm-generic/io.h:735:19: warning: 'temp' may be used uninitialized in this function [-Wmaybe-uninitialized]
    #define iowrite32 iowrite32
                      ^~~~~~~~~
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:25:6: note: 'temp' was declared here
     u32 temp;
         ^~~~
--
   In file included from arch/s390/include/asm/io.h:76:0,
                    from include/linux/io.h:13,
                    from include/linux/pci.h:39,
                    from drivers/net//ethernet/freescale/enetc/enetc.h:5,
                    from drivers/net//ethernet/freescale/enetc/enetc_qos.c:4:
   drivers/net//ethernet/freescale/enetc/enetc_qos.c: In function 'enetc_setup_tc_taprio':
>> include/asm-generic/io.h:735:19: warning: 'temp' may be used uninitialized in this function [-Wmaybe-uninitialized]
    #define iowrite32 iowrite32
                      ^~~~~~~~~
   drivers/net//ethernet/freescale/enetc/enetc_qos.c:25:6: note: 'temp' was declared here
     u32 temp;
         ^~~~

vim +/temp +735 include/asm-generic/io.h

9216efafc52ff9 Thierry Reding 2014-10-01  733  
9216efafc52ff9 Thierry Reding 2014-10-01  734  #ifndef iowrite32
9216efafc52ff9 Thierry Reding 2014-10-01 @735  #define iowrite32 iowrite32
9216efafc52ff9 Thierry Reding 2014-10-01  736  static inline void iowrite32(u32 value, volatile void __iomem *addr)
9216efafc52ff9 Thierry Reding 2014-10-01  737  {
9216efafc52ff9 Thierry Reding 2014-10-01  738  	writel(value, addr);
9216efafc52ff9 Thierry Reding 2014-10-01  739  }
9216efafc52ff9 Thierry Reding 2014-10-01  740  #endif
9216efafc52ff9 Thierry Reding 2014-10-01  741  

:::::: The code at line 735 was first introduced by commit
:::::: 9216efafc52ff99e9351ef60de5fcafc2bc8adb6 asm-generic/io.h: Reconcile I/O accessor overrides

:::::: TO: Thierry Reding <treding@nvidia.com>
:::::: CC: Thierry Reding <treding@nvidia.com>

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 56364 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
                   ` (3 preceding siblings ...)
  2019-11-12 12:31 ` kbuild test robot
@ 2019-11-12 12:43 ` kbuild test robot
  2019-11-12 16:03 ` Ivan Khoronzhuk
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2019-11-12 12:43 UTC (permalink / raw)
  To: Po Liu
  Cc: kbuild-all, Claudiu Manoil, davem, linux-kernel, netdev,
	vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li

[-- Attachment #1: Type: text/plain, Size: 5138 bytes --]

Hi Po,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]
[also build test WARNING on v5.4-rc7 next-20191112]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Po-Liu/enetc-Configure-the-Time-Aware-Scheduler-via-tc-taprio-offload/20191112-193235
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git ca22d6977b9b4ab0fd2e7909b57e32ba5b95046f
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/freescale/enetc/enetc_qos.c: In function 'enetc_setup_tc_taprio':
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:25:6: warning: 'temp' may be used uninitialized in this function [-Wmaybe-uninitialized]
     u32 temp;
         ^~~~

vim +/temp +25 drivers/net/ethernet/freescale/enetc/enetc_qos.c

    13	
    14	static int enetc_setup_taprio(struct net_device *ndev,
    15				      struct tc_taprio_qopt_offload *admin_conf)
    16	{
    17		struct enetc_ndev_priv *priv = netdev_priv(ndev);
    18		struct enetc_cbd cbd = {.cmd = 0};
    19		struct tgs_gcl_conf *gcl_config;
    20		struct tgs_gcl_data *gcl_data;
    21		struct gce *gce;
    22		dma_addr_t dma;
    23		u16 data_size;
    24		u16 gcl_len;
  > 25		u32 temp;
    26		int i;
    27	
    28		gcl_len = admin_conf->num_entries;
    29		if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
    30			return -EINVAL;
    31	
    32		if (admin_conf->enable) {
    33			enetc_wr(&priv->si->hw,
    34				 ENETC_QBV_PTGCR_OFFSET,
    35				 temp & (~ENETC_QBV_TGE));
    36			usleep_range(10, 20);
    37			enetc_wr(&priv->si->hw,
    38				 ENETC_QBV_PTGCR_OFFSET,
    39				 temp | ENETC_QBV_TGE);
    40		} else {
    41			enetc_wr(&priv->si->hw,
    42				 ENETC_QBV_PTGCR_OFFSET,
    43				 temp & (~ENETC_QBV_TGE));
    44			return 0;
    45		}
    46	
    47		/* Configure the (administrative) gate control list using the
    48		 * control BD descriptor.
    49		 */
    50		gcl_config = &cbd.gcl_conf;
    51	
    52		data_size = sizeof(struct tgs_gcl_data) + gcl_len * sizeof(struct gce);
    53	
    54		gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
    55		if (!gcl_data)
    56			return -ENOMEM;
    57	
    58		gce = (struct gce *)(gcl_data + 1);
    59	
    60		/* Since no initial state config in taprio, set gates open as default.
    61		 */
    62		gcl_config->atc = 0xff;
    63		gcl_config->acl_len = cpu_to_le16(gcl_len);
    64	
    65		if (!admin_conf->base_time) {
    66			gcl_data->btl =
    67				cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
    68			gcl_data->bth =
    69				cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
    70		} else {
    71			gcl_data->btl =
    72				cpu_to_le32(lower_32_bits(admin_conf->base_time));
    73			gcl_data->bth =
    74				cpu_to_le32(upper_32_bits(admin_conf->base_time));
    75		}
    76	
    77		gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
    78		gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
    79	
    80		for (i = 0; i < gcl_len; i++) {
    81			struct tc_taprio_sched_entry *temp_entry;
    82			struct gce *temp_gce = gce + i;
    83	
    84			temp_entry = &admin_conf->entries[i];
    85	
    86			temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);
    87			temp_gce->period = cpu_to_le32(temp_entry->interval);
    88		}
    89	
    90		cbd.length = cpu_to_le16(data_size);
    91		cbd.status_flags = 0;
    92	
    93		dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
    94				     data_size, DMA_TO_DEVICE);
    95		if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
    96			netdev_err(priv->si->ndev, "DMA mapping failed!\n");
    97			kfree(gcl_data);
    98			return -ENOMEM;
    99		}
   100	
   101		cbd.addr[0] = lower_32_bits(dma);
   102		cbd.addr[1] = upper_32_bits(dma);
   103		cbd.cls = BDCR_CMD_PORT_GCL;
   104	
   105		/* Updated by ENETC on completion of the configuration
   106		 * command. A zero value indicates success.
   107		 */
   108		cbd.status_flags = 0;
   109	
   110		enetc_send_cmd(priv->si, &cbd);
   111	
   112		dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
   113		kfree(gcl_data);
   114	
   115		return 0;
   116	}
   117	

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 67129 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12 11:54     ` Claudiu Manoil
@ 2019-11-12 13:46       ` Simon Horman
  0 siblings, 0 replies; 36+ messages in thread
From: Simon Horman @ 2019-11-12 13:46 UTC (permalink / raw)
  To: Claudiu Manoil
  Cc: Po Liu, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Tue, Nov 12, 2019 at 11:54:29AM +0000, Claudiu Manoil wrote:
> >-----Original Message-----
> >From: Po Liu <po.liu@nxp.com>
> [...]
> >> -----Original Message-----
> >> From: Simon Horman <simon.horman@netronome.com>
> [...]
> >> > +/* class 5, command 0 */
> >> > +struct tgs_gcl_conf {
> >> > +     u8      atc;    /* init gate value */
> >> > +     u8      res[7];
> >> > +     union {
> >> > +             struct {
> >> > +                     u8      res1[4];
> >> > +                     __le16  acl_len;
> >>
> >> Given that u* types are used in this structure I think le16 would be more
> >> appropriate than __le16.
> >
> >Here keep the same code style of this .h file. I think it is better to have
> >another patch to fix them all. Do you agree?
> >
> 
> I don't see why "le16" would be more appropriate than "__le16" in this context.
> The "__leXX" types are widely used in kernel drivers and not only, to annotate the
> endianess of the hardware.  These are generic types defined din "include/uapi/linux/types.h".
> Whereas "leXX" are defined in "fs/ntfs/types.h", and there's no usage of these types
> in other h/w device drivers (I didn't find any).  Am I missing anything?

My point is a cosmetic one:
I think that __u8 goes with __le16, while u8 goes with le16.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12 11:19   ` [EXT] " Po Liu
  2019-11-12 11:54     ` Claudiu Manoil
@ 2019-11-12 13:50     ` Simon Horman
  1 sibling, 0 replies; 36+ messages in thread
From: Simon Horman @ 2019-11-12 13:50 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Tue, Nov 12, 2019 at 11:19:43AM +0000, Po Liu wrote:

...

> > > +/* class 5, command 0 */
> > > +struct tgs_gcl_conf {
> > > +     u8      atc;    /* init gate value */
> > > +     u8      res[7];
> > > +     union {
> > > +             struct {
> > > +                     u8      res1[4];
> > > +                     __le16  acl_len;
> > 
> > Given that u* types are used in this structure I think le16 would be more
> > appropriate than __le16.
>  
> Here keep the same code style of this .h file. I think it is better to have another patch to fix them all. Do you agree?
> 
> > 

> > > +                     u8      res2[2];
> > > +             };
> > > +             struct {
> > > +                     u32 cctl;
> > > +                     u32 ccth;
> > > +             };
> > 
> > I'm a little surprised to see host endian values in a structure that appears to be
> > written to hardware. Is this intentional?
> 
> Will remove.

If the HW defines these fields then I think its fine to leave them,
though with the correct byte-order.

I was more asking if it is intentional that the value for these
fields, when sent to the HW, is always zero in the context of this
patch-set. Likewise elsewhere.

...

> > > +
> > > +     gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
> > > +     gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
> > > +
> > > +     for (i = 0; i < gcl_len; i++) {
> > > +             struct tc_taprio_sched_entry *temp_entry;
> > > +             struct gce *temp_gce = gce + i;
> > > +
> > > +             temp_entry = &admin_conf->entries[i];
> > > +
> > > +             temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);
> > 
> >         Gate is a u8 followed by 3 reserved bytes.
> >         Perhaps there needs to be some bounds checking on
> >         the value stored there given that the source is 32bits wide.
> > 
> >         Also, its not clear to me that the above logic, which I assume
> >         takes the last significant byte of a 32bit value, works on
> >         big endian systems as the 32bit value is always little endian.
> 
> temp_entry->gate_mask is 32bit for wide possible input. Here change to hardware set 8bit wide.
> Can it just be like:
> 	temp_gce->gate = (u8) temp_entry->gate_mask;

I think that would be better.
Perhaps its best to also mask out the unwanted bits.

...

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
                   ` (4 preceding siblings ...)
  2019-11-12 12:43 ` kbuild test robot
@ 2019-11-12 16:03 ` Ivan Khoronzhuk
  2019-11-12 22:57 ` [RFC PATCH] enetc: enetc_setup_tc_mqprio() can be static kbuild test robot
  2019-11-12 22:57 ` [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload kbuild test robot
  7 siblings, 0 replies; 36+ messages in thread
From: Ivan Khoronzhuk @ 2019-11-12 16:03 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Mon, Nov 11, 2019 at 04:41:26AM +0000, Po Liu wrote:
>ENETC supports in hardware for time-based egress shaping according
>to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
>hardware offload method qdisc tc-taprio method.
>Also update cbdr writeback to up level since control bd ring may
>writeback data to control bd ring.
>
>Signed-off-by: Po Liu <Po.Liu@nxp.com>
>Singed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
>Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
>---
> drivers/net/ethernet/freescale/enetc/Makefile |   1 +
> drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> drivers/net/ethernet/freescale/enetc/enetc.h  |   2 +
> .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
> .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
> 6 files changed, 285 insertions(+), 22 deletions(-)
> create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
>
>diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
>index d200c27c3bf6..389f722efc43 100644
>--- a/drivers/net/ethernet/freescale/enetc/Makefile
>+++ b/drivers/net/ethernet/freescale/enetc/Makefile
>@@ -5,6 +5,7 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
> obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
> fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
> fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
>+fsl-enetc-$(CONFIG_NET_SCH_TAPRIO) += enetc_qos.o
>
> obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
> fsl-enetc-vf-y := enetc_vf.o $(common-objs)
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
>index 3e8f9819f08c..d58dbc2c4270 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc.c
>+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
>@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
> 	return 0;
> }
>
>-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>-		   void *type_data)
>+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
> {
> 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> 	struct tc_mqprio_qopt *mqprio = type_data;
>@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> 	u8 num_tc;
> 	int i;
>
>-	if (type != TC_SETUP_QDISC_MQPRIO)
>-		return -EOPNOTSUPP;
>-
> 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
> 	num_tc = mqprio->num_tc;
>
>@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> 	return 0;
> }
>
>+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>+		   void *type_data)
>+{
>+	switch (type) {
>+	case TC_SETUP_QDISC_MQPRIO:
>+		return enetc_setup_tc_mqprio(ndev, type_data);

This patch is for taprio offload, I see that mqprio is related and is part of
taprio offload configuration. But taprio offload has own mqprio settings.
The taprio mqprio part is not offloaded with TC_SETUP_QDISC_MQPRIO.

So, a combination of mqprio and tario qdiscs used.
Could you please share the commands were used for your setup?

And couple interesting questions about all of this:
- The taprio qdisc has to have mqprio settings, but if it's done with
mqprio then it just skipped (by reading tc class num).
- If no separate mqprio qdisc configuration then mqprio conf from taprio
is set, who should restore tc mappings when taprio qdisc is unloaded?

Maybe there is reason to implement TC_SETUP_QDISC_MQPRIO offload in taprio
since it's required feature?

Would be better to move changes for mqprio in separate patch with explanation.

>+	case TC_SETUP_QDISC_TAPRIO:
>+		return enetc_setup_tc_taprio(ndev, type_data);
>+	default:
>+		return -EOPNOTSUPP;
>+	}
>+}
>+
> struct net_device_stats *enetc_get_stats(struct net_device *ndev)
> {
> 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
>index 541b4e2073fe..8676631041d5 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc.h
>+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
>@@ -244,3 +244,5 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
> void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
> int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
> int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
>+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
>+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>index de466b71bf8f..201cbc362e33 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
> 		r->bd_count;
> }
>
>-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
>+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> {
> 	struct enetc_cbdr *ring = &si->cbd_ring;
> 	int timeout = ENETC_CBDR_TIMEOUT;
>@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> 	if (!timeout)
> 		return -EBUSY;
>
>+	/* CBD may writeback data, feedback up level */
>+	*cbd = *dest_cbd;
>+
> 	enetc_clean_cbdr(si);
>
> 	return 0;
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>index 88276299f447..75a7c0f1f8ce 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>@@ -18,6 +18,7 @@
> #define ENETC_SICTR0	0x18
> #define ENETC_SICTR1	0x1c
> #define ENETC_SIPCAPR0	0x20
>+#define ENETC_SIPCAPR0_QBV	BIT(4)
> #define ENETC_SIPCAPR0_RSS	BIT(8)
> #define ENETC_SIPCAPR1	0x24
> #define ENETC_SITGTGR	0x30
>@@ -148,6 +149,12 @@ enum enetc_bdr_type {TX, RX};
> #define ENETC_PORT_BASE		0x10000
> #define ENETC_PMR		0x0000
> #define ENETC_PMR_EN	GENMASK(18, 16)
>+#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
>+#define ENETC_PMR_PSPEED_10M 0x000
>+#define ENETC_PMR_PSPEED_100M 0x100
>+#define ENETC_PMR_PSPEED_1000M 0x200
>+#define ENETC_PMR_PSPEED_2500M 0x400
>+
> #define ENETC_PSR		0x0004 /* RO */
> #define ENETC_PSIPMR		0x0018
> #define ENETC_PSIPMR_SET_UP(n)	BIT(n) /* n = SI index */
>@@ -440,22 +447,6 @@ union enetc_rx_bd {
> #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
> #define ENETC_MAX_NUM_VFS	2
>
>-struct enetc_cbd {
>-	union {
>-		struct {
>-			__le32 addr[2];
>-			__le32 opt[4];
>-		};
>-		__le32 data[6];
>-	};
>-	__le16 index;
>-	__le16 length;
>-	u8 cmd;
>-	u8 cls;
>-	u8 _res;
>-	u8 status_flags;
>-};
>-
> #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
> #define ENETC_CBD_STATUS_MASK	0xf
>
>@@ -554,3 +545,130 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
> 	val |= ENETC_TBMR_SET_PRIO(prio);
> 	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
> }
>+
>+enum bdcr_cmd_class {
>+	BDCR_CMD_UNSPEC = 0,
>+	BDCR_CMD_MAC_FILTER,
>+	BDCR_CMD_VLAN_FILTER,
>+	BDCR_CMD_RSS,
>+	BDCR_CMD_RFS,
>+	BDCR_CMD_PORT_GCL,
>+	BDCR_CMD_RECV_CLASSIFIER,
>+	__BDCR_CMD_MAX_LEN,
>+	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
>+};
>+
>+/* class 5, command 0 */
>+struct tgs_gcl_conf {
>+	u8	atc;	/* init gate value */
>+	u8	res[7];
>+	union {
>+		struct {
>+			u8	res1[4];
>+			__le16	acl_len;
>+			u8	res2[2];
>+		};
>+		struct {
>+			u32 cctl;
>+			u32 ccth;
>+		};
>+	};
>+};
>+
>+#define ENETC_CBDR_SGL_IOMEN	BIT(0)
>+#define ENETC_CBDR_SGL_IPVEN	BIT(3)
>+#define ENETC_CBDR_SGL_GTST	BIT(4)
>+#define ENETC_CBDR_SGL_IPV_MASK 0xe
>+
>+/* gate control list entry */
>+struct gce {
>+	u32	period;
>+	u8	gate;
>+	u8	res[3];
>+};
>+
>+/* tgs_gcl_conf address point to this data space */
>+struct tgs_gcl_data {
>+	u32	btl;
>+	u32	bth;
>+	u32	ct;
>+	u32	cte;
>+};
>+
>+/* class 5, command 1 */
>+struct tgs_gcl_query {
>+		u8	res[12];
>+		union {
>+			struct {
>+				__le16	acl_len; /* admin list length */
>+				__le16	ocl_len; /* operation list length */
>+			};
>+			struct {
>+				u16 admin_list_len;
>+				u16 oper_list_len;
>+			};
>+		};
>+};
>+
>+/* tgs_gcl_query command response data format */
>+struct tgs_gcl_resp {
>+	u32 abtl;	/* base time */
>+	u32 abth;
>+	u32 act;	/* cycle time */
>+	u32 acte;	/* cycle time extend */
>+	u32 cctl;	/* config change time */
>+	u32 ccth;
>+	u32 obtl;	/* operation base time */
>+	u32 obth;
>+	u32 oct;	/* operation cycle time */
>+	u32 octe;	/* operation cycle time extend */
>+	u32 ccel;	/* config change error */
>+	u32 cceh;
>+};
>+
>+struct enetc_cbd {
>+	union{
>+		struct {
>+			__le32	addr[2];
>+			union {
>+				__le32	opt[4];
>+				struct tgs_gcl_conf	gcl_conf;
>+				struct tgs_gcl_query	gcl_query;
>+			};
>+		};	/* Long format */
>+		__le32 data[6];
>+	};
>+	__le16 index;
>+	__le16 length;
>+	u8 cmd;
>+	u8 cls;
>+	u8 _res;
>+	u8 status_flags;
>+};
>+
>+#define ENETC_PTCFPR(n)		(0x1910 + (n) * 4) /* n = [0 ..7] */
>+#define ENETC_FPE		BIT(31)
>+
>+/* Port capability register 0 */
>+#define ENETC_PCAPR0_PSFPM	BIT(10)
>+#define ENETC_PCAPR0_PSFP	BIT(9)
>+#define ENETC_PCAPR0_TSN	BIT(4)
>+#define ENETC_PCAPR0_QBU	BIT(3)
>+
>+/* port time gating control register */
>+#define ENETC_QBV_PTGCR_OFFSET		0x11a00
>+#define ENETC_QBV_TGE			0x80000000
>+#define ENETC_QBV_TGPE			BIT(30)
>+#define ENETC_QBV_TGDROP_DISABLE	BIT(29)
>+
>+/* Port time gating capability register */
>+#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
>+#define ENETC_QBV_MAX_GCL_LEN_MASK	0xffff
>+
>+/* Port time gating admin gate list status register */
>+#define ENETC_QBV_PTGAGLSR_OFFSET	0x11a10
>+#define ENETC_QBV_CFG_PEND_MASK	0x00000002
>+
>+#define ENETC_TGLSTR			0xa200
>+#define ENETC_TGS_MIN_DIS_MASK		0x80000000
>+#define ENETC_MIN_LOOKAHEAD_MASK	0xffff
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
>new file mode 100644
>index 000000000000..036bb39c7a0b
>--- /dev/null
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
>@@ -0,0 +1,130 @@
>+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
>+/* Copyright 2019 NXP */
>+
>+#include "enetc.h"
>+
>+#include <net/pkt_sched.h>
>+
>+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
>+{
>+	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
>+		& ENETC_QBV_MAX_GCL_LEN_MASK;
>+}
>+
>+static int enetc_setup_taprio(struct net_device *ndev,
>+			      struct tc_taprio_qopt_offload *admin_conf)
>+{
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	struct enetc_cbd cbd = {.cmd = 0};
>+	struct tgs_gcl_conf *gcl_config;
>+	struct tgs_gcl_data *gcl_data;
>+	struct gce *gce;
>+	dma_addr_t dma;
>+	u16 data_size;
>+	u16 gcl_len;
>+	u32 temp;
>+	int i;
>+
>+	gcl_len = admin_conf->num_entries;
>+	if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
>+		return -EINVAL;
>+
>+	if (admin_conf->enable) {
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 temp & (~ENETC_QBV_TGE));
>+		usleep_range(10, 20);
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 temp | ENETC_QBV_TGE);
>+	} else {
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 temp & (~ENETC_QBV_TGE));
>+		return 0;
>+	}
>+
>+	/* Configure the (administrative) gate control list using the
>+	 * control BD descriptor.
>+	 */
>+	gcl_config = &cbd.gcl_conf;
>+
>+	data_size = sizeof(struct tgs_gcl_data) + gcl_len * sizeof(struct gce);
>+
>+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
>+	if (!gcl_data)
>+		return -ENOMEM;
>+
>+	gce = (struct gce *)(gcl_data + 1);
>+
>+	/* Since no initial state config in taprio, set gates open as default.
>+	 */
>+	gcl_config->atc = 0xff;
>+	gcl_config->acl_len = cpu_to_le16(gcl_len);
>+
>+	if (!admin_conf->base_time) {
>+		gcl_data->btl =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
>+		gcl_data->bth =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
>+	} else {
>+		gcl_data->btl =
>+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
>+		gcl_data->bth =
>+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
>+	}
>+
>+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
>+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
>+
>+	for (i = 0; i < gcl_len; i++) {
>+		struct tc_taprio_sched_entry *temp_entry;
>+		struct gce *temp_gce = gce + i;
>+
>+		temp_entry = &admin_conf->entries[i];
>+
>+		temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);
>+		temp_gce->period = cpu_to_le32(temp_entry->interval);
>+	}
>+
>+	cbd.length = cpu_to_le16(data_size);
>+	cbd.status_flags = 0;
>+
>+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
>+			     data_size, DMA_TO_DEVICE);
>+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
>+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
>+		kfree(gcl_data);
>+		return -ENOMEM;
>+	}
>+
>+	cbd.addr[0] = lower_32_bits(dma);
>+	cbd.addr[1] = upper_32_bits(dma);
>+	cbd.cls = BDCR_CMD_PORT_GCL;
>+
>+	/* Updated by ENETC on completion of the configuration
>+	 * command. A zero value indicates success.
>+	 */
>+	cbd.status_flags = 0;
>+
>+	enetc_send_cmd(priv->si, &cbd);
>+
>+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
>+	kfree(gcl_data);
>+
>+	return 0;
>+}
>+
>+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
>+{
>+	struct tc_taprio_qopt_offload *taprio = type_data;
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	int i;
>+
>+	for (i = 0; i < priv->num_tx_rings; i++)
>+		enetc_set_bdr_prio(&priv->si->hw,
>+				   priv->tx_ring[i]->index,
>+				   taprio->enable ? i : 0);
>+
>+	return enetc_setup_taprio(ndev, taprio);
>+}
>-- 
>2.17.1
>

-- 
Regards,
Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12  8:42   ` [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-12  8:42     ` [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-12 18:57     ` David Miller
  2019-11-12 21:10     ` Ivan Khoronzhuk
  2 siblings, 0 replies; 36+ messages in thread
From: David Miller @ 2019-11-12 18:57 UTC (permalink / raw)
  To: po.liu
  Cc: claudiu.manoil, linux-kernel, netdev, vinicius.gomes,
	vladimir.oltean, alexandru.marginean, xiaoliang.yang_1, roy.zang,
	mingkai.hu, jerry.huang, leoyang.li

From: Po Liu <po.liu@nxp.com>
Date: Tue, 12 Nov 2019 08:42:49 +0000

> ENETC supports in hardware for time-based egress shaping according
> to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
> hardware offload method qdisc tc-taprio method.
> Also update cbdr writeback to up level since control bd ring may
> writeback data to control bd ring.
> 
> Signed-off-by: Po Liu <Po.Liu@nxp.com>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>

Applied.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-12  8:42     ` [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-12 18:57       ` David Miller
  2019-11-14  5:12       ` [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  1 sibling, 0 replies; 36+ messages in thread
From: David Miller @ 2019-11-12 18:57 UTC (permalink / raw)
  To: po.liu
  Cc: claudiu.manoil, linux-kernel, netdev, vinicius.gomes,
	vladimir.oltean, alexandru.marginean, xiaoliang.yang_1, roy.zang,
	mingkai.hu, jerry.huang, leoyang.li

From: Po Liu <po.liu@nxp.com>
Date: Tue, 12 Nov 2019 08:42:55 +0000

> ENETC has a register PSPEED to indicate the link speed of hardware.
> It is need to update accordingly. PSPEED field needs to be updated
> with the port speed for QBV scheduling purposes. Or else there is
> chance for gate slot not free by frame taking the MAC if PSPEED and
> phy speed not match. So update PSPEED when link adjust. This is
> implement by the adjust_link.
> 
> Signed-off-by: Po Liu <Po.Liu@nxp.com>
> Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Applied.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12  9:41 ` Simon Horman
  2019-11-12 11:19   ` [EXT] " Po Liu
@ 2019-11-12 18:58   ` David Miller
  2019-11-12 18:59     ` David Miller
  1 sibling, 1 reply; 36+ messages in thread
From: David Miller @ 2019-11-12 18:58 UTC (permalink / raw)
  To: simon.horman
  Cc: po.liu, claudiu.manoil, linux-kernel, netdev, vinicius.gomes,
	vladimir.oltean, alexandru.marginean, xiaoliang.yang_1, roy.zang,
	mingkai.hu, jerry.huang, leoyang.li


Oops, I didn't see this feedback because v2 had been posted.

I'll revert that now.

Please address Simon's feedback on these two patches, and then post a v3,
thank you.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12 18:58   ` David Miller
@ 2019-11-12 18:59     ` David Miller
  2019-11-13  4:55       ` [EXT] " Po Liu
  0 siblings, 1 reply; 36+ messages in thread
From: David Miller @ 2019-11-12 18:59 UTC (permalink / raw)
  To: simon.horman
  Cc: po.liu, claudiu.manoil, linux-kernel, netdev, vinicius.gomes,
	vladimir.oltean, alexandru.marginean, xiaoliang.yang_1, roy.zang,
	mingkai.hu, jerry.huang, leoyang.li

From: David Miller <davem@davemloft.net>
Date: Tue, 12 Nov 2019 10:58:59 -0800 (PST)

> 
> Oops, I didn't see this feedback because v2 had been posted.
> 
> I'll revert that now.
> 
> Please address Simon's feedback on these two patches, and then post a v3,
> thank you.

Also, v2 doesn't even compile :-(

In file included from drivers/net/ethernet/freescale/enetc/enetc.h:14,
                 from drivers/net/ethernet/freescale/enetc/enetc_qos.c:4:
drivers/net/ethernet/freescale/enetc/enetc_qos.c: In function ‘enetc_setup_tc_taprio’:
drivers/net/ethernet/freescale/enetc/enetc_hw.h:308:32: warning: ‘temp’ may be used uninitialized in this function [-Wmaybe-uninitialized]
 #define enetc_wr_reg(reg, val) iowrite32((val), (reg))
                                ^~~~~~~~~
drivers/net/ethernet/freescale/enetc/enetc_qos.c:59:6: note: ‘temp’ was declared here
  u32 temp;
      ^~~~
ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
make[1]: *** [scripts/Makefile.modpost:94: __modpost] Error 1
make: *** [Makefile:1282: modules] Error 2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-11  4:41 ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
  2019-11-12  8:42   ` [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-12  9:41   ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Simon Horman
@ 2019-11-12 19:59   ` kbuild test robot
  2 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2019-11-12 19:59 UTC (permalink / raw)
  To: Po Liu
  Cc: kbuild-all, Claudiu Manoil, davem, linux-kernel, netdev,
	vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li

[-- Attachment #1: Type: text/plain, Size: 1320 bytes --]

Hi Po,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on net-next/master]
[also build test ERROR on v5.4-rc7 next-20191111]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Po-Liu/enetc-Configure-the-Time-Aware-Scheduler-via-tc-taprio-offload/20191112-193235
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git ca22d6977b9b4ab0fd2e7909b57e32ba5b95046f
config: i386-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.4.0-14) 7.4.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
   ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 70224 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12  8:42   ` [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-12  8:42     ` [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
  2019-11-12 18:57     ` [v2,net-next, " David Miller
@ 2019-11-12 21:10     ` Ivan Khoronzhuk
  2019-11-13  3:45       ` [EXT] " Po Liu
  2 siblings, 1 reply; 36+ messages in thread
From: Ivan Khoronzhuk @ 2019-11-12 21:10 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

Hello,

On Tue, Nov 12, 2019 at 08:42:49AM +0000, Po Liu wrote:
>ENETC supports in hardware for time-based egress shaping according
>to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
>hardware offload method qdisc tc-taprio method.
>Also update cbdr writeback to up level since control bd ring may
>writeback data to control bd ring.
>
>Signed-off-by: Po Liu <Po.Liu@nxp.com>
>Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
>Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
>---
>changes:
>- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
>  configurations will result in link errors.
>  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
>  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
>  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
>  tsn feature, or else, return not support.
>
> drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
> drivers/net/ethernet/freescale/enetc/Makefile |   1 +
> drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
> .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
> .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
> 7 files changed, 300 insertions(+), 22 deletions(-)
> create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
>

[...]

>
>@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> 	return 0;
> }
>
>+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>+		   void *type_data)
>+{
>+	switch (type) {
>+	case TC_SETUP_QDISC_MQPRIO:
>+		return enetc_setup_tc_mqprio(ndev, type_data);
Sorry didn't see v2, so i duplicate my question here:

This patch is for taprio offload, I see that mqprio is related and is part of
taprio offload configuration. But taprio offload has own mqprio settings.
The taprio mqprio part is not offloaded with TC_SETUP_QDISC_MQPRIO.

So, a combination of mqprio and tario qdiscs used.
Could you please share the commands were used for your setup?

And couple interesting questions about all of this:
- The taprio qdisc has to have mqprio settings, but if it's done with
mqprio then it just skipped (by reading tc class num).
- If no separate mqprio qdisc configuration then mqprio conf from taprio
is set, who should restore tc mappings when taprio qdisc is unloaded?
Maybe there is reason to implement TC_SETUP_QDISC_MQPRIO offload in taprio
since it's required feature?

Would be better to move changes for mqprio in separate patch with explanation.

>+	case TC_SETUP_QDISC_TAPRIO:
>+		return enetc_setup_tc_taprio(ndev, type_data);
>+	default:
>+		return -EOPNOTSUPP;
>+	}
>+}
>+

[...]

>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
>new file mode 100644
>index 000000000000..036bb39c7a0b
>--- /dev/null
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c

[...]

>+static int enetc_setup_taprio(struct net_device *ndev,
>+			      struct tc_taprio_qopt_offload *admin_conf)
>+{
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	struct enetc_cbd cbd = {.cmd = 0};
>+	struct tgs_gcl_conf *gcl_config;
>+	struct tgs_gcl_data *gcl_data;
>+	struct gce *gce;
>+	dma_addr_t dma;
>+	u16 data_size;
>+	u16 gcl_len;
>+	u32 temp;
>+	int i;
>+
>+	gcl_len = admin_conf->num_entries;
>+	if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
>+		return -EINVAL;
>+
>+	if (admin_conf->enable) {
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 temp & (~ENETC_QBV_TGE));
>+		usleep_range(10, 20);
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 temp | ENETC_QBV_TGE);
>+	} else {
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 temp & (~ENETC_QBV_TGE));
>+		return 0;
>+	}

Better do the upper qbv enable/disable procedure closer to enetc_send_cmd() or
at least after kzalloc that can fail, no need to restore then.

>+
>+	/* Configure the (administrative) gate control list using the
>+	 * control BD descriptor.
>+	 */
>+	gcl_config = &cbd.gcl_conf;
>+
>+	data_size = sizeof(struct tgs_gcl_data) + gcl_len * sizeof(struct gce);
>+
>+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
>+	if (!gcl_data)
>+		return -ENOMEM;
>+
>+	gce = (struct gce *)(gcl_data + 1);
>+
>+	/* Since no initial state config in taprio, set gates open as default.
>+	 */
tc-taprio and IEEE Qbv allows to change configuration in flight, so that oper
state is active till new admin start time. So, here comment says it does
initial state config, if in-flight feature is not supported then error has to
be returned instead of silently rewriting configuration. But if it can be
implemented then state should be remembered/verified in order to not brake oper
configuration?

>+	gcl_config->atc = 0xff;
>+	gcl_config->acl_len = cpu_to_le16(gcl_len);

Ok, this is maximum number of schedules.
According to tc-taprio it's possible to set cycle period more then schedules
actually can consume. If cycle time is more, then last gate's state can be
kept till the end of cycle. But if last schedule has it's own interval set
then gates should be closed till the end of cycle or no? if it has to be closed,
then one more endl schedule should be present closing gates at the end of list
for the rest cycle time. Can be implemented in h/w but just to be sure, how it's
done in h/w?

>+
>+	if (!admin_conf->base_time) {
>+		gcl_data->btl =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
>+		gcl_data->bth =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
>+	} else {
>+		gcl_data->btl =
>+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
>+		gcl_data->bth =
>+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
>+	}
>+
>+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
>+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);

Not sure it's good idea to write values w/o verification, The cycle time and
time extension is 64 values, so it's supposed them to be more then 4,3
seconds, it's probably not a case, but better return error if it's more.

>+
>+	for (i = 0; i < gcl_len; i++) {
>+		struct tc_taprio_sched_entry *temp_entry;
>+		struct gce *temp_gce = gce + i;
>+
>+		temp_entry = &admin_conf->entries[i];
>+
>+		temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);

So, gate_mask can have up to 32 traffic classes? :-|.

>+		temp_gce->period = cpu_to_le32(temp_entry->interval);

So, the interval can be up to 4.3 seconds for one schedule?
That is, one cycle can be one schedule.
great.

>+	}

There is no schedule cmd set, so only SetGateStates is supported?
But anyway it's Ok.

>+
>+	cbd.length = cpu_to_le16(data_size);
>+	cbd.status_flags = 0;
>+
>+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
>+			     data_size, DMA_TO_DEVICE);
>+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
>+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
>+		kfree(gcl_data);
>+		return -ENOMEM;
>+	}
>+
>+	cbd.addr[0] = lower_32_bits(dma);
>+	cbd.addr[1] = upper_32_bits(dma);
>+	cbd.cls = BDCR_CMD_PORT_GCL;
>+
>+	/* Updated by ENETC on completion of the configuration
>+	 * command. A zero value indicates success.
>+	 */
>+	cbd.status_flags = 0;

It's updated on completion by setting 0 on success, then why it's here
set to 0 but not 1 and not verified afterwards?

>+
>+	enetc_send_cmd(priv->si, &cbd);
>+
>+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
>+	kfree(gcl_data);
>+
>+	return 0;
>+}
>+
>+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
>+{
>+	struct tc_taprio_qopt_offload *taprio = type_data;
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	int i;
>+
>+	for (i = 0; i < priv->num_tx_rings; i++)
>+		enetc_set_bdr_prio(&priv->si->hw,
>+				   priv->tx_ring[i]->index,
>+				   taprio->enable ? i : 0);

then why enable/disable at the beginning for whole qbv scheduler, maybe
better do it together? Or better say, what if setup_taprio failed, who restore
configuration?

>+
>+	return enetc_setup_taprio(ndev, taprio);
>+}
>-- 
>2.17.1
>

-- 
Regards,
Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [RFC PATCH] enetc: enetc_setup_tc_mqprio() can be static
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
                   ` (5 preceding siblings ...)
  2019-11-12 16:03 ` Ivan Khoronzhuk
@ 2019-11-12 22:57 ` kbuild test robot
  2019-11-12 22:57 ` [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload kbuild test robot
  7 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2019-11-12 22:57 UTC (permalink / raw)
  To: Po Liu
  Cc: kbuild-all, Claudiu Manoil, davem, linux-kernel, netdev,
	vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li


Fixes: 0ffc020dc8f3 ("enetc: Configure the Time-Aware Scheduler via tc-taprio offload")
Signed-off-by: kbuild test robot <lkp@intel.com>
---
 enetc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index d58dbc2c4270e..724dc90bf87a2 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -1427,7 +1427,7 @@ int enetc_close(struct net_device *ndev)
 	return 0;
 }
 
-int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
+static int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct tc_mqprio_qopt *mqprio = type_data;

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
                   ` (6 preceding siblings ...)
  2019-11-12 22:57 ` [RFC PATCH] enetc: enetc_setup_tc_mqprio() can be static kbuild test robot
@ 2019-11-12 22:57 ` kbuild test robot
  7 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2019-11-12 22:57 UTC (permalink / raw)
  To: Po Liu
  Cc: kbuild-all, Claudiu Manoil, davem, linux-kernel, netdev,
	vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li

Hi Po,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]
[also build test WARNING on v5.4-rc7 next-20191111]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Po-Liu/enetc-Configure-the-Time-Aware-Scheduler-via-tc-taprio-offload/20191112-193235
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git ca22d6977b9b4ab0fd2e7909b57e32ba5b95046f
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-29-g781bc5d-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/net/ethernet/freescale/enetc/enetc.c:1430:5: sparse: sparse: symbol 'enetc_setup_tc_mqprio' was not declared. Should it be static?
--
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:66:31: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int [usertype] btl @@    got restrunsigned int [usertype] btl @@
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:66:31: sparse:    expected unsigned int [usertype] btl
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:66:31: sparse:    got restricted __le32 [usertype]
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:68:31: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int [usertype] bth @@    got restrunsigned int [usertype] bth @@
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:68:31: sparse:    expected unsigned int [usertype] bth
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:68:31: sparse:    got restricted __le32 [usertype]
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:71:31: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int [usertype] btl @@    got restrunsigned int [usertype] btl @@
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:71:31: sparse:    expected unsigned int [usertype] btl
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:71:31: sparse:    got restricted __le32 [usertype]
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:73:31: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int [usertype] bth @@    got restrunsigned int [usertype] bth @@
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:73:31: sparse:    expected unsigned int [usertype] bth
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:73:31: sparse:    got restricted __le32 [usertype]
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:77:22: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int [usertype] ct @@    got restrunsigned int [usertype] ct @@
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:77:22: sparse:    expected unsigned int [usertype] ct
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:77:22: sparse:    got restricted __le32 [usertype]
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:78:23: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int [usertype] cte @@    got restrunsigned int [usertype] cte @@
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:78:23: sparse:    expected unsigned int [usertype] cte
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:78:23: sparse:    got restricted __le32 [usertype]
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:86:32: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned char [usertype] gate @@    got restunsigned char [usertype] gate @@
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:86:32: sparse:    expected unsigned char [usertype] gate
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:86:32: sparse:    got restricted __le32 [usertype]
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:87:34: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int [usertype] period @@    got restrunsigned int [usertype] period @@
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:87:34: sparse:    expected unsigned int [usertype] period
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:87:34: sparse:    got restricted __le32 [usertype]
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:101:21: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le32 @@    got unsignerestricted __le32 @@
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:101:21: sparse:    expected restricted __le32
>> drivers/net/ethernet/freescale/enetc/enetc_qos.c:101:21: sparse:    got unsigned int [usertype]
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:102:21: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le32 @@    got unsignerestricted __le32 @@
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:102:21: sparse:    expected restricted __le32
   drivers/net/ethernet/freescale/enetc/enetc_qos.c:102:21: sparse:    got unsigned int [usertype]

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [EXT] Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12 21:10     ` Ivan Khoronzhuk
@ 2019-11-13  3:45       ` Po Liu
  2019-11-13 13:41         ` Ivan Khoronzhuk
  0 siblings, 1 reply; 36+ messages in thread
From: Po Liu @ 2019-11-13  3:45 UTC (permalink / raw)
  To: Ivan Khoronzhuk
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

Hi Ivan,

> -----Original Message-----
> From: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
> Sent: 2019年11月13日 5:10
> To: Po Liu <po.liu@nxp.com>
> Cc: Claudiu Manoil <claudiu.manoil@nxp.com>; davem@davemloft.net; linux-
> kernel@vger.kernel.org; netdev@vger.kernel.org; vinicius.gomes@intel.com;
> Vladimir Oltean <vladimir.oltean@nxp.com>; Alexandru Marginean
> <alexandru.marginean@nxp.com>; Xiaoliang Yang
> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
> <leoyang.li@nxp.com>
> Subject: [EXT] Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler
> via tc-taprio offload
> 
> Caution: EXT Email
> 
> Hello,
> 
> On Tue, Nov 12, 2019 at 08:42:49AM +0000, Po Liu wrote:
> >ENETC supports in hardware for time-based egress shaping according to
> >IEEE 802.1Qbv. This patch implement the Qbv enablement by the hardware
> >offload method qdisc tc-taprio method.
> >Also update cbdr writeback to up level since control bd ring may
> >writeback data to control bd ring.
> >
> >Signed-off-by: Po Liu <Po.Liu@nxp.com>
> >Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> >Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> >---
> >changes:
> >- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
> >  configurations will result in link errors.
> >  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
> >  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
> >  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
> >  tsn feature, or else, return not support.
> >
> > drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
> > drivers/net/ethernet/freescale/enetc/Makefile |   1 +
> > drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> > drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
> > .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> > .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
> > .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
> > 7 files changed, 300 insertions(+), 22 deletions(-) create mode 100644
> > drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >
> 
> [...]
> 
> >
> >@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum
> tc_setup_type type,
> >       return 0;
> > }
> >
> >+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> >+                 void *type_data)
> >+{
> >+      switch (type) {
> >+      case TC_SETUP_QDISC_MQPRIO:
> >+              return enetc_setup_tc_mqprio(ndev, type_data);
> Sorry didn't see v2, so i duplicate my question here:
> 
> This patch is for taprio offload, I see that mqprio is related and is part of taprio
> offload configuration. But taprio offload has own mqprio settings.
> The taprio mqprio part is not offloaded with TC_SETUP_QDISC_MQPRIO.
> 
> So, a combination of mqprio and tario qdiscs used.
> Could you please share the commands were used for your setup?
> 

Example command: 
tc qdisc replace dev eth0 parent root handle 100  taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 01 sched-entry S 02 300000 flags 0x2

> And couple interesting questions about all of this:
> - The taprio qdisc has to have mqprio settings, but if it's done with mqprio then
> it just skipped (by reading tc class num).
> - If no separate mqprio qdisc configuration then mqprio conf from taprio is set,
> who should restore tc mappings when taprio qdisc is unloaded?
> Maybe there is reason to implement TC_SETUP_QDISC_MQPRIO offload in
> taprio since it's required feature?

Mqprio offload with TC_SETUP_QDISC_MQPRIO would be good or even the plus with num_tc would fix some hack. This has a discussion with Vinicius Gomes for a future patch fix. 
I know the problem is the mqprio will be set after the offload function. But offload function may use some for hardware set.

> Would be better to move changes for mqprio in separate patch with
> explanation.
> 
> >+      case TC_SETUP_QDISC_TAPRIO:
> >+              return enetc_setup_tc_taprio(ndev, type_data);
> >+      default:
> >+              return -EOPNOTSUPP;
> >+      }
> >+}
> >+
> 
> [...]
> 
> >diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >new file mode 100644
> >index 000000000000..036bb39c7a0b
> >--- /dev/null
> >+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> 
> [...]
> 
> >+static int enetc_setup_taprio(struct net_device *ndev,
> >+                            struct tc_taprio_qopt_offload *admin_conf)
> >+{
> >+      struct enetc_ndev_priv *priv = netdev_priv(ndev);
> >+      struct enetc_cbd cbd = {.cmd = 0};
> >+      struct tgs_gcl_conf *gcl_config;
> >+      struct tgs_gcl_data *gcl_data;
> >+      struct gce *gce;
> >+      dma_addr_t dma;
> >+      u16 data_size;
> >+      u16 gcl_len;
> >+      u32 temp;
> >+      int i;
> >+
> >+      gcl_len = admin_conf->num_entries;
> >+      if (gcl_len > enetc_get_max_gcl_len(&priv->si->hw))
> >+              return -EINVAL;
> >+
> >+      if (admin_conf->enable) {
> >+              enetc_wr(&priv->si->hw,
> >+                       ENETC_QBV_PTGCR_OFFSET,
> >+                       temp & (~ENETC_QBV_TGE));
> >+              usleep_range(10, 20);
> >+              enetc_wr(&priv->si->hw,
> >+                       ENETC_QBV_PTGCR_OFFSET,
> >+                       temp | ENETC_QBV_TGE);
> >+      } else {
> >+              enetc_wr(&priv->si->hw,
> >+                       ENETC_QBV_PTGCR_OFFSET,
> >+                       temp & (~ENETC_QBV_TGE));
> >+              return 0;
> >+      }
> 
> Better do the upper qbv enable/disable procedure closer to enetc_send_cmd()
> or at least after kzalloc that can fail, no need to restore then.

After saving the 'if' suggest by Simon Horman, the enable part could move close to the cmd().

> 
> >+
> >+      /* Configure the (administrative) gate control list using the
> >+       * control BD descriptor.
> >+       */
> >+      gcl_config = &cbd.gcl_conf;
> >+
> >+      data_size = sizeof(struct tgs_gcl_data) + gcl_len *
> >+ sizeof(struct gce);
> >+
> >+      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
> >+      if (!gcl_data)
> >+              return -ENOMEM;
> >+
> >+      gce = (struct gce *)(gcl_data + 1);
> >+
> >+      /* Since no initial state config in taprio, set gates open as default.
> >+       */
> tc-taprio and IEEE Qbv allows to change configuration in flight, so that oper
> state is active till new admin start time. So, here comment says it does initial
> state config, if in-flight feature is not supported then error has to be returned
> instead of silently rewriting configuration. But if it can be implemented then
> state should be remembered/verified in order to not brake oper configuration?

I think this is ok as per standard. Also see this comment in
net/sched/sch_taprio.c:

	/* Until the schedule starts, all the queues are open */
I would change the comment.

> >+      gcl_config->atc = 0xff;
> >+      gcl_config->acl_len = cpu_to_le16(gcl_len);
> 
> Ok, this is maximum number of schedules.
> According to tc-taprio it's possible to set cycle period more then schedules
> actually can consume. If cycle time is more, then last gate's state can be kept
> till the end of cycle. But if last schedule has it's own interval set then gates
> should be closed till the end of cycle or no? if it has to be closed, then one more
> endl schedule should be present closing gates at the end of list for the rest cycle
> time. Can be implemented in h/w but just to be sure, how it's done in h/w?
> 
There is already check the list len in up code.
if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
	return -EINVAL;
gcl_len = admin_conf->num_entries; 

> >+
> >+      if (!admin_conf->base_time) {
> >+              gcl_data->btl =
> >+                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
> >+              gcl_data->bth =
> >+                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
> >+      } else {
> >+              gcl_data->btl =
> >+                      cpu_to_le32(lower_32_bits(admin_conf->base_time));
> >+              gcl_data->bth =
> >+                      cpu_to_le32(upper_32_bits(admin_conf->base_time));
> >+      }
> >+
> >+      gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
> >+      gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
> 
> Not sure it's good idea to write values w/o verification, The cycle time and time
> extension is 64 values, so it's supposed them to be more then 4,3 seconds, it's
> probably not a case, but better return error if it's more.
> 

Can add a check for cycle time and extension since type not match.
 
> >+
> >+      for (i = 0; i < gcl_len; i++) {
> >+              struct tc_taprio_sched_entry *temp_entry;
> >+              struct gce *temp_gce = gce + i;
> >+
> >+              temp_entry = &admin_conf->entries[i];
> >+
> >+              temp_gce->gate = cpu_to_le32(temp_entry->gate_mask);
> 
> So, gate_mask can have up to 32 traffic classes? :-|.

Gate_mask is defined u32 type. Simon has suggested endian issue. Would change in next patch.

> 
> >+              temp_gce->period = cpu_to_le32(temp_entry->interval);
> 
> So, the interval can be up to 4.3 seconds for one schedule?
> That is, one cycle can be one schedule.
> great.
> 
> >+      }
> 
> There is no schedule cmd set, so only SetGateStates is supported?
> But anyway it's Ok.
> 
> >+
> >+      cbd.length = cpu_to_le16(data_size);
> >+      cbd.status_flags = 0;
> >+
> >+      dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
> >+                           data_size, DMA_TO_DEVICE);
> >+      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
> >+              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
> >+              kfree(gcl_data);
> >+              return -ENOMEM;
> >+      }
> >+
> >+      cbd.addr[0] = lower_32_bits(dma);
> >+      cbd.addr[1] = upper_32_bits(dma);
> >+      cbd.cls = BDCR_CMD_PORT_GCL;
> >+
> >+      /* Updated by ENETC on completion of the configuration
> >+       * command. A zero value indicates success.
> >+       */
> >+      cbd.status_flags = 0;
> 
> It's updated on completion by setting 0 on success, then why it's here set to 0
> but not 1 and not verified afterwards?
>

This byte is feedback by hardware after enetc_send_cmd. Hardware require the cbd space set status_flags 0 before send to hardware.
 No choice of larger than 0 before send to hardware.
But you mind me the enetc_send_cmd() need to check return value.

> >+
> >+      enetc_send_cmd(priv->si, &cbd);
> >+
> >+      dma_unmap_single(&priv->si->pdev->dev, dma, data_size,
> DMA_TO_DEVICE);
> >+      kfree(gcl_data);
> >+
> >+      return 0;
> >+}
> >+
> >+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) {
> >+      struct tc_taprio_qopt_offload *taprio = type_data;
> >+      struct enetc_ndev_priv *priv = netdev_priv(ndev);
> >+      int i;
> >+
> >+      for (i = 0; i < priv->num_tx_rings; i++)
> >+              enetc_set_bdr_prio(&priv->si->hw,
> >+                                 priv->tx_ring[i]->index,
> >+                                 taprio->enable ? i : 0);
> 
> then why enable/disable at the beginning for whole qbv scheduler, maybe
> better do it together? Or better say, what if setup_taprio failed, who restore
> configuration?

You remind me the enetc_send_cmd() need to check return value.

> >+
> >+      return enetc_setup_taprio(ndev, taprio); }
> >--
> >2.17.1
> >
> 
> --
> Regards,
> Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12 18:59     ` David Miller
@ 2019-11-13  4:55       ` Po Liu
  0 siblings, 0 replies; 36+ messages in thread
From: Po Liu @ 2019-11-13  4:55 UTC (permalink / raw)
  To: David Miller, simon.horman
  Cc: Claudiu Manoil, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

Hi David,

Thanks!
Br,
Po Liu

> -----Original Message-----
> From: David Miller <davem@davemloft.net>
> Sent: 2019年11月13日 3:00
> To: simon.horman@netronome.com
> Cc: Po Liu <po.liu@nxp.com>; Claudiu Manoil <claudiu.manoil@nxp.com>;
> linux-kernel@vger.kernel.org; netdev@vger.kernel.org;
> vinicius.gomes@intel.com; Vladimir Oltean <vladimir.oltean@nxp.com>;
> Alexandru Marginean <alexandru.marginean@nxp.com>; Xiaoliang Yang
> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
> <leoyang.li@nxp.com>
> Subject: [EXT] Re: [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via
> tc-taprio offload
> 
> Caution: EXT Email
> 
> From: David Miller <davem@davemloft.net>
> Date: Tue, 12 Nov 2019 10:58:59 -0800 (PST)
> 
> >
> > Oops, I didn't see this feedback because v2 had been posted.
> >
> > I'll revert that now.
> >
> > Please address Simon's feedback on these two patches, and then post a
> > v3, thank you.
> 
> Also, v2 doesn't even compile :-(
> 
> In file included from drivers/net/ethernet/freescale/enetc/enetc.h:14,
>                  from drivers/net/ethernet/freescale/enetc/enetc_qos.c:4:
> drivers/net/ethernet/freescale/enetc/enetc_qos.c: In function
> ʽenetc_setup_tc_taprioʼ:
> drivers/net/ethernet/freescale/enetc/enetc_hw.h:308:32: warning: ʽtempʼ may
> be used uninitialized in this function [-Wmaybe-uninitialized]  #define
> enetc_wr_reg(reg, val) iowrite32((val), (reg))
>                                 ^~~~~~~~~
> drivers/net/ethernet/freescale/enetc/enetc_qos.c:59:6: note: ʽtempʼ was
> declared here

More delete one line. Will fix in v3.

>   u32 temp;
>       ^~~~
> ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-
> enetc-vf.ko] undefined!
> ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-
> enetc-vf.ko] undefined!
> make[1]: *** [scripts/Makefile.modpost:94: __modpost] Error 1
> make: *** [Makefile:1282: modules] Error 2

I got this situation. 
It happened when set module mode, since vf drvier should not own the taprio set.
Thanks!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [EXT] Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-13  3:45       ` [EXT] " Po Liu
@ 2019-11-13 13:41         ` Ivan Khoronzhuk
  2019-11-14  4:39           ` Po Liu
  0 siblings, 1 reply; 36+ messages in thread
From: Ivan Khoronzhuk @ 2019-11-13 13:41 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Wed, Nov 13, 2019 at 03:45:08AM +0000, Po Liu wrote:
>Hi Ivan,
>
>> -----Original Message-----
>> From: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
>> Sent: 2019年11月13日 5:10
>> To: Po Liu <po.liu@nxp.com>
>> Cc: Claudiu Manoil <claudiu.manoil@nxp.com>; davem@davemloft.net; linux-
>> kernel@vger.kernel.org; netdev@vger.kernel.org; vinicius.gomes@intel.com;
>> Vladimir Oltean <vladimir.oltean@nxp.com>; Alexandru Marginean
>> <alexandru.marginean@nxp.com>; Xiaoliang Yang
>> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
>> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
>> <leoyang.li@nxp.com>
>> Subject: [EXT] Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler
>> via tc-taprio offload
>>
>> Caution: EXT Email
>>
>> Hello,
>>
>> On Tue, Nov 12, 2019 at 08:42:49AM +0000, Po Liu wrote:
>> >ENETC supports in hardware for time-based egress shaping according to
>> >IEEE 802.1Qbv. This patch implement the Qbv enablement by the hardware
>> >offload method qdisc tc-taprio method.
>> >Also update cbdr writeback to up level since control bd ring may
>> >writeback data to control bd ring.
>> >
>> >Signed-off-by: Po Liu <Po.Liu@nxp.com>
>> >Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
>> >Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
>> >---
>> >changes:
>> >- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
>> >  configurations will result in link errors.
>> >  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
>> >  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
>> >  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
>> >  tsn feature, or else, return not support.
>> >
>> > drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
>> > drivers/net/ethernet/freescale/enetc/Makefile |   1 +
>> > drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
>> > drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
>> > .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
>> > .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
>> > .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
>> > 7 files changed, 300 insertions(+), 22 deletions(-) create mode 100644
>> > drivers/net/ethernet/freescale/enetc/enetc_qos.c
>> >
>>
>> [...]
>>
>> >
>> >@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum
>> tc_setup_type type,
>> >       return 0;
>> > }
>> >
>> >+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>> >+                 void *type_data)
>> >+{
>> >+      switch (type) {
>> >+      case TC_SETUP_QDISC_MQPRIO:
>> >+              return enetc_setup_tc_mqprio(ndev, type_data);
>> Sorry didn't see v2, so i duplicate my question here:
>>
>> This patch is for taprio offload, I see that mqprio is related and is part of taprio
>> offload configuration. But taprio offload has own mqprio settings.
>> The taprio mqprio part is not offloaded with TC_SETUP_QDISC_MQPRIO.
>>
>> So, a combination of mqprio and tario qdiscs used.
>> Could you please share the commands were used for your setup?
>>
>
>Example command:
>tc qdisc replace dev eth0 parent root handle 100  taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 01 sched-entry S 02 300000 flags 0x2

So, the TC_SETUP_QDISC_MQPRIO is really not required here, and mqprio qdisc is
not used. Then why is it here, should be placed in separate patch at least.

But even the comb mqprio qdisc and taprio qdisc are used together then taprio
requires hw offload also. I'm Ok to add it later to taprio, and I'm asking
about it because I need it also, what ever way it could be added.

Not clear how you combined mqprio qdisc and taprio now to get it working
From this command:

tc qdisc replace dev eth0 parent root handle 100  taprio num_tc 8 map 0 1 2 3 4 
5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 01 sched-entry S 02 
300000 flags 0x2

I can conclude that some default h/w mapping (one to one) were used and no need
to use mqprio qdisc, the command above is enough.

Is it true?
Then move it to spearate patch please as it's not taprio related yet.

>
>> And couple interesting questions about all of this:
>> - The taprio qdisc has to have mqprio settings, but if it's done with mqprio then
>> it just skipped (by reading tc class num).
>> - If no separate mqprio qdisc configuration then mqprio conf from taprio is set,
>> who should restore tc mappings when taprio qdisc is unloaded?
>> Maybe there is reason to implement TC_SETUP_QDISC_MQPRIO offload in
>> taprio since it's required feature?
>

[...]

>>
>> >+
>> >+      /* Configure the (administrative) gate control list using the
>> >+       * control BD descriptor.
>> >+       */
>> >+      gcl_config = &cbd.gcl_conf;
>> >+
>> >+      data_size = sizeof(struct tgs_gcl_data) + gcl_len *
>> >+ sizeof(struct gce);
>> >+
>> >+      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
>> >+      if (!gcl_data)
>> >+              return -ENOMEM;
>> >+
>> >+      gce = (struct gce *)(gcl_data + 1);
>> >+
>> >+      /* Since no initial state config in taprio, set gates open as default.
>> >+       */
>> tc-taprio and IEEE Qbv allows to change configuration in flight, so that oper
>> state is active till new admin start time. So, here comment says it does initial
>> state config, if in-flight feature is not supported then error has to be returned
>> instead of silently rewriting configuration. But if it can be implemented then
>> state should be remembered/verified in order to not brake oper configuration?
>
>I think this is ok as per standard. Also see this comment in
>net/sched/sch_taprio.c:

From the code above (duplicate for convenience):
      if (admin_conf->enable) {
              enetc_wr(&priv->si->hw,
                       ENETC_QBV_PTGCR_OFFSET,
                       temp & (~ENETC_QBV_TGE));
              usleep_range(10, 20);
              enetc_wr(&priv->si->hw,
                       ENETC_QBV_PTGCR_OFFSET,
                       temp | ENETC_QBV_TGE);
      } else {
              enetc_wr(&priv->si->hw,
                       ENETC_QBV_PTGCR_OFFSET,
                       temp & (~ENETC_QBV_TGE));
              return 0;
      }

I see that's not true, as Simon noted, you have same command:

enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET, temp & (~ENETC_QBV_TGE));

before enabling and for disabling. I guess it's stop command, that is disable
qbv. So, before enabling new configuration with enetc_setup_tc(), the tario is
inited|cleared|reseted|rebooted|defaulted|offed but not updated. It means no
in-flight capabilities or they are ignored.

JFI, it's possible to do first time:

tc qdisc replace dev eth0 parent root handle 100  taprio num_tc 8 map 0 1 2 3 4 
5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 01 sched-entry S 02 
300000 flags 0x2

and then:

tc qdisc replace dev eth0 parent root handle 100  taprio base-time 01 
sched-entry S 02 200000 flags 0x2

Do it many times, but w/o mqprio configuration.

So, this function must return error if it cannot be done, as above commands
suppose that configuration can be updated in runtime, that is, set ADMIN cycle
while OPER cycle is still active for some time and not broken like it's done
now. If it can be achieved then no need to do
enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET, temp & (~ENETC_QBV_TGE));
when admin_conf->enable.

So or return error, or do it appropriately.

>
>	/* Until the schedule starts, all the queues are open */
>I would change the comment.
>
>> >+      gcl_config->atc = 0xff;
>> >+      gcl_config->acl_len = cpu_to_le16(gcl_len);
>>
>> Ok, this is maximum number of schedules.
>> According to tc-taprio it's possible to set cycle period more then schedules
>> actually can consume. If cycle time is more, then last gate's state can be kept
>> till the end of cycle. But if last schedule has it's own interval set then gates
>> should be closed till the end of cycle or no? if it has to be closed, then one more
>> endl schedule should be present closing gates at the end of list for the rest cycle
>> time. Can be implemented in h/w but just to be sure, how it's done in h/w?
>>
>There is already check the list len in up code.
>if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
>	return -EINVAL;
>gcl_len = admin_conf->num_entries;

I mean +1 schedule to finalize the cycle with closed gates if last schedule
has provided time interval. If I set couple schedules, with intervals, and cycle
time more then those schedules consume, then I suppose the gates closed for the
rest time of cycle, probably.

Example:

sched1 ----> shced2 ----> time w/o scheds -> cycle end
gate 1       gate 2       no gates

But if shced2 is last one then gate 2 is opened till the end of cycle.
So, to close gate one more shched is needed with closed gates to finalize it.
Or it's supposed that gate2 is opened till the end of cycle,
How is it in you case. Or this is can be provided by configuration from tc?

It's question not statement. Just though. Anyway i'll verify later it can be
done with tc and how it's done in sw version, just interesting how your h/w
works.

>
>> >+
>> >+      if (!admin_conf->base_time) {
>> >+              gcl_data->btl =
>> >+                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
>> >+              gcl_data->bth =
>> >+                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));

[...]

-- 
Regards,
Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [EXT] Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-13 13:41         ` Ivan Khoronzhuk
@ 2019-11-14  4:39           ` Po Liu
  0 siblings, 0 replies; 36+ messages in thread
From: Po Liu @ 2019-11-14  4:39 UTC (permalink / raw)
  To: Ivan Khoronzhuk
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

Hi Ivan,


> -----Original Message-----
> From: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
> Sent: 2019年11月13日 21:42
> To: Po Liu <po.liu@nxp.com>
> Cc: Claudiu Manoil <claudiu.manoil@nxp.com>; davem@davemloft.net; linux-
> kernel@vger.kernel.org; netdev@vger.kernel.org; vinicius.gomes@intel.com;
> Vladimir Oltean <vladimir.oltean@nxp.com>; Alexandru Marginean
> <alexandru.marginean@nxp.com>; Xiaoliang Yang
> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
> <leoyang.li@nxp.com>
> Subject: Re: [EXT] Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware
> Scheduler via tc-taprio offload
> 
> Caution: EXT Email
> 
> On Wed, Nov 13, 2019 at 03:45:08AM +0000, Po Liu wrote:
> >Hi Ivan,
> >
> >> -----Original Message-----
> >> From: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
> >> Sent: 2019年11月13日 5:10
> >> To: Po Liu <po.liu@nxp.com>
> >> Cc: Claudiu Manoil <claudiu.manoil@nxp.com>; davem@davemloft.net;
> >> linux- kernel@vger.kernel.org; netdev@vger.kernel.org;
> >> vinicius.gomes@intel.com; Vladimir Oltean <vladimir.oltean@nxp.com>;
> >> Alexandru Marginean <alexandru.marginean@nxp.com>; Xiaoliang Yang
> >> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
> >> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
> >> <leoyang.li@nxp.com>
> >> Subject: [EXT] Re: [v2,net-next, 1/2] enetc: Configure the Time-Aware
> >> Scheduler via tc-taprio offload
> >>
> >> Caution: EXT Email
> >>
> >> Hello,
> >>
> >> On Tue, Nov 12, 2019 at 08:42:49AM +0000, Po Liu wrote:
> >> >ENETC supports in hardware for time-based egress shaping according
> >> >to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
> >> >hardware offload method qdisc tc-taprio method.
> >> >Also update cbdr writeback to up level since control bd ring may
> >> >writeback data to control bd ring.
> >> >
> >> >Signed-off-by: Po Liu <Po.Liu@nxp.com>
> >> >Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> >> >Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> >> >---
> >> >changes:
> >> >- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
> >> >  configurations will result in link errors.
> >> >  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
> >> >  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS
> >> >depends
> >> >  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable
> >> >this
> >> >  tsn feature, or else, return not support.
> >> >
> >> > drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
> >> > drivers/net/ethernet/freescale/enetc/Makefile |   1 +
> >> > drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> >> > drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
> >> > .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> >> > .../net/ethernet/freescale/enetc/enetc_hw.h   | 150 ++++++++++++++++--
> >> > .../net/ethernet/freescale/enetc/enetc_qos.c  | 130 +++++++++++++++
> >> > 7 files changed, 300 insertions(+), 22 deletions(-) create mode
> >> > 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >> >
> >>
> >> [...]
> >>
> >> >
> >> >@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev,
> >> >enum
> >> tc_setup_type type,
> >> >       return 0;
> >> > }
> >> >
> >> >+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> >> >+                 void *type_data)
> >> >+{
> >> >+      switch (type) {
> >> >+      case TC_SETUP_QDISC_MQPRIO:
> >> >+              return enetc_setup_tc_mqprio(ndev, type_data);
> >> Sorry didn't see v2, so i duplicate my question here:
> >>
> >> This patch is for taprio offload, I see that mqprio is related and is
> >> part of taprio offload configuration. But taprio offload has own mqprio
> settings.
> >> The taprio mqprio part is not offloaded with TC_SETUP_QDISC_MQPRIO.
> >>
> >> So, a combination of mqprio and tario qdiscs used.
> >> Could you please share the commands were used for your setup?
> >>
> >
> >Example command:
> >tc qdisc replace dev eth0 parent root handle 100  taprio num_tc 8 map 0
> >1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 01
> >sched-entry S 02 300000 flags 0x2
> 
> So, the TC_SETUP_QDISC_MQPRIO is really not required here, and mqprio qdisc
> is not used. Then why is it here, should be placed in separate patch at least.
> 

Taprio is not fully copy the mqprio but refer the mqprio feature.  I don't think there is 
Problem for them all list in driver. Some person may not use taprio at all.

> But even the comb mqprio qdisc and taprio qdisc are used together then taprio
> requires hw offload also. I'm Ok to add it later to taprio, and I'm asking about it
> because I need it also, what ever way it could be added.
> 
> Not clear how you combined mqprio qdisc and taprio now to get it working
> From this command:
>
> tc qdisc replace dev eth0 parent root handle 100  taprio num_tc 8 map 0 1 2 3
> 4
> 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 01 sched-
> entry S 02
> 300000 flags 0x2
> 
> I can conclude that some default h/w mapping (one to one) were used and no
> need to use mqprio qdisc, the command above is enough.
> 
> Is it true?
> Then move it to spearate patch please as it's not taprio related yet.
 
As mentioned, to set the queue mapping it is require the data_type include the mqprio parameter.
So here hardware set it as default. Without the settting, taprio would not say it is implement the offload.
So I don’t think it is proper to seperate another patch. 

> >
> >> And couple interesting questions about all of this:
> >> - The taprio qdisc has to have mqprio settings, but if it's done with
> >> mqprio then it just skipped (by reading tc class num).
> >> - If no separate mqprio qdisc configuration then mqprio conf from
> >> taprio is set, who should restore tc mappings when taprio qdisc is unloaded?
> >> Maybe there is reason to implement TC_SETUP_QDISC_MQPRIO offload in
> >> taprio since it's required feature?
> >
> 
> [...]
> 
> >>
> >> >+
> >> >+      /* Configure the (administrative) gate control list using the
> >> >+       * control BD descriptor.
> >> >+       */
> >> >+      gcl_config = &cbd.gcl_conf;
> >> >+
> >> >+      data_size = sizeof(struct tgs_gcl_data) + gcl_len *
> >> >+ sizeof(struct gce);
> >> >+
> >> >+      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
> >> >+      if (!gcl_data)
> >> >+              return -ENOMEM;
> >> >+
> >> >+      gce = (struct gce *)(gcl_data + 1);
> >> >+
> >> >+      /* Since no initial state config in taprio, set gates open as default.
> >> >+       */
> >> tc-taprio and IEEE Qbv allows to change configuration in flight, so
> >> that oper state is active till new admin start time. So, here comment
> >> says it does initial state config, if in-flight feature is not
> >> supported then error has to be returned instead of silently rewriting
> >> configuration. But if it can be implemented then state should be
> remembered/verified in order to not brake oper configuration?
> >
> >I think this is ok as per standard. Also see this comment in
> >net/sched/sch_taprio.c:
> 
> From the code above (duplicate for convenience):
>       if (admin_conf->enable) {
>               enetc_wr(&priv->si->hw,
>                        ENETC_QBV_PTGCR_OFFSET,
>                        temp & (~ENETC_QBV_TGE));
>               usleep_range(10, 20);
>               enetc_wr(&priv->si->hw,
>                        ENETC_QBV_PTGCR_OFFSET,
>                        temp | ENETC_QBV_TGE);
>       } else {
>               enetc_wr(&priv->si->hw,
>                        ENETC_QBV_PTGCR_OFFSET,
>                        temp & (~ENETC_QBV_TGE));
>               return 0;
>       }
> 
> I see that's not true, as Simon noted, you have same command:
> 
> enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET, temp &
> (~ENETC_QBV_TGE));
> 
> before enabling and for disabling. I guess it's stop command, that is disable qbv.
> So, before enabling new configuration with enetc_setup_tc(), the tario is
> inited|cleared|reseted|rebooted|defaulted|offed but not updated. It
> inited|cleared|reseted|rebooted|defaulted|means no
> in-flight capabilities or they are ignored.

The Qbv spec do not show the disable before enable. 
Here is hardware workaround to avoid the hardware run into unknow state.

> 
> JFI, it's possible to do first time:
> 
> tc qdisc replace dev eth0 parent root handle 100  taprio num_tc 8 map 0 1 2 3
> 4
> 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 01 sched-
> entry S 02
> 300000 flags 0x2
> 
> and then:
> 
> tc qdisc replace dev eth0 parent root handle 100  taprio base-time 01 sched-
> entry S 02 200000 flags 0x2
> 
> Do it many times, but w/o mqprio configuration.
> 
> So, this function must return error if it cannot be done, as above commands
> suppose that configuration can be updated in runtime, that is, set ADMIN cycle
> while OPER cycle is still active for some time and not broken like it's done now.
> If it can be achieved then no need to do enetc_wr(&priv->si->hw,
> ENETC_QBV_PTGCR_OFFSET, temp & (~ENETC_QBV_TGE)); when admin_conf-
> >enable.
> 
> So or return error, or do it appropriately.
> 
> >
> >       /* Until the schedule starts, all the queues are open */ I would
> >change the comment.
> >
> >> >+      gcl_config->atc = 0xff;
> >> >+      gcl_config->acl_len = cpu_to_le16(gcl_len);
> >>
> >> Ok, this is maximum number of schedules.
> >> According to tc-taprio it's possible to set cycle period more then
> >> schedules actually can consume. If cycle time is more, then last
> >> gate's state can be kept till the end of cycle. But if last schedule
> >> has it's own interval set then gates should be closed till the end of
> >> cycle or no? if it has to be closed, then one more endl schedule
> >> should be present closing gates at the end of list for the rest cycle time. Can
> be implemented in h/w but just to be sure, how it's done in h/w?
> >>
> >There is already check the list len in up code.
> >if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
> >       return -EINVAL;
> >gcl_len = admin_conf->num_entries;
> 
> I mean +1 schedule to finalize the cycle with closed gates if last schedule has
> provided time interval. If I set couple schedules, with intervals, and cycle time
> more then those schedules consume, then I suppose the gates closed for the
> rest time of cycle, probably.
> 
> Example:
> 
> sched1 ----> shced2 ----> time w/o scheds -> cycle end
> gate 1       gate 2       no gates
> 
> But if shced2 is last one then gate 2 is opened till the end of cycle.
> So, to close gate one more shched is needed with closed gates to finalize it.
> Or it's supposed that gate2 is opened till the end of cycle, How is it in you case.
> Or this is can be provided by configuration from tc?
> 
> It's question not statement. Just though. Anyway i'll verify later it can be done
> with tc and how it's done in sw version, just interesting how your h/w works.

What user command set the gate list would set into the hardware.
 We have detail setting in the user manual which you can have it try.

> >
> >> >+
> >> >+      if (!admin_conf->base_time) {
> >> >+              gcl_data->btl =
> >> >+                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
> >> >+              gcl_data->bth =
> >> >+                      cpu_to_le32(enetc_rd(&priv->si->hw,
> >> >+ ENETC_SICTR1));
> 
> [...]
> 
> --
> Regards,
> Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-12  8:42     ` [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
  2019-11-12 18:57       ` David Miller
@ 2019-11-14  5:12       ` Po Liu
  2019-11-14  5:12         ` [v3,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
  2019-11-14 18:51         ` [v3,net-next, " Ivan Khoronzhuk
  1 sibling, 2 replies; 36+ messages in thread
From: Po Liu @ 2019-11-14  5:12 UTC (permalink / raw)
  To: Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC supports in hardware for time-based egress shaping according
to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
hardware offload method qdisc tc-taprio method.
Also update cbdr writeback to up level since control bd ring may
writeback data to control bd ring.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
---
changes:
v2:
- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
  configurations will result in link errors.
  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
  tsn feature, or else, return not support.
v3:
- fix the compiling vf module failure issue:
  ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
  ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
- remove defines not used in this patch
- fix hardware endian issue
- make the qbv set code more rubust with some error condition may occur.

 drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
 drivers/net/ethernet/freescale/enetc/Makefile |   2 +
 drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
 drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
 .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
 .../net/ethernet/freescale/enetc/enetc_hw.h   |  84 ++++++++---
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 134 ++++++++++++++++++
 7 files changed, 239 insertions(+), 22 deletions(-)
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c

diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index c219587bd334..491659fe3e35 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING
 	  allocation has not been supported and it is too expensive to use
 	  extended RX BDs if timestamping is not used, this option enables
 	  extended RX BDs in order to support hardware timestamping.
+
+config FSL_ENETC_QOS
+	bool "ENETC hardware Time-sensitive Network support"
+	depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
+	help
+	  There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
+	  /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
+	  enable/disable from user space via Qos commands(tc). In the kernel
+	  side, it can be loaded by Qos driver. Currently, it is only support
+	  taprio(802.1Qbv).
diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index d200c27c3bf6..d0db33e5b6b7 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -5,9 +5,11 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
 obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
 fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
 fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
+fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
 
 obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
 fsl-enetc-vf-y := enetc_vf.o $(common-objs)
+fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
 
 obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o
 fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 3e8f9819f08c..d58dbc2c4270 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
 	return 0;
 }
 
-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
-		   void *type_data)
+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct tc_mqprio_qopt *mqprio = type_data;
@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	u8 num_tc;
 	int i;
 
-	if (type != TC_SETUP_QDISC_MQPRIO)
-		return -EOPNOTSUPP;
-
 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
 	num_tc = mqprio->num_tc;
 
@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	return 0;
 }
 
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+		   void *type_data)
+{
+	switch (type) {
+	case TC_SETUP_QDISC_MQPRIO:
+		return enetc_setup_tc_mqprio(ndev, type_data);
+	case TC_SETUP_QDISC_TAPRIO:
+		return enetc_setup_tc_taprio(ndev, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 struct net_device_stats *enetc_get_stats(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 541b4e2073fe..8ca2f97050c8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
 void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
+
+#ifdef CONFIG_FSL_ENETC_QOS
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+#else
+#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+#endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
index de466b71bf8f..201cbc362e33 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
 		r->bd_count;
 }
 
-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 {
 	struct enetc_cbdr *ring = &si->cbd_ring;
 	int timeout = ENETC_CBDR_TIMEOUT;
@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 	if (!timeout)
 		return -EBUSY;
 
+	/* CBD may writeback data, feedback up level */
+	*cbd = *dest_cbd;
+
 	enetc_clean_cbdr(si);
 
 	return 0;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 88276299f447..df6b35dc3534 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -18,6 +18,7 @@
 #define ENETC_SICTR0	0x18
 #define ENETC_SICTR1	0x1c
 #define ENETC_SIPCAPR0	0x20
+#define ENETC_SIPCAPR0_QBV	BIT(4)
 #define ENETC_SIPCAPR0_RSS	BIT(8)
 #define ENETC_SIPCAPR1	0x24
 #define ENETC_SITGTGR	0x30
@@ -440,22 +441,6 @@ union enetc_rx_bd {
 #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
 #define ENETC_MAX_NUM_VFS	2
 
-struct enetc_cbd {
-	union {
-		struct {
-			__le32 addr[2];
-			__le32 opt[4];
-		};
-		__le32 data[6];
-	};
-	__le16 index;
-	__le16 length;
-	u8 cmd;
-	u8 cls;
-	u8 _res;
-	u8 status_flags;
-};
-
 #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
 #define ENETC_CBD_STATUS_MASK	0xf
 
@@ -554,3 +539,70 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
 	val |= ENETC_TBMR_SET_PRIO(prio);
 	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
 }
+
+enum bdcr_cmd_class {
+	BDCR_CMD_UNSPEC = 0,
+	BDCR_CMD_MAC_FILTER,
+	BDCR_CMD_VLAN_FILTER,
+	BDCR_CMD_RSS,
+	BDCR_CMD_RFS,
+	BDCR_CMD_PORT_GCL,
+	BDCR_CMD_RECV_CLASSIFIER,
+	__BDCR_CMD_MAX_LEN,
+	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
+};
+
+/* class 5, command 0 */
+struct tgs_gcl_conf {
+	u8	atc;	/* init gate value */
+	u8	res[7];
+	struct {
+		u8	res1[4];
+		__le16	acl_len;
+		u8	res2[2];
+	};
+};
+
+/* gate control list entry */
+struct gce {
+	__le32	period;
+	u8	gate;
+	u8	res[3];
+};
+
+/* tgs_gcl_conf address point to this data space */
+struct tgs_gcl_data {
+	__le32		btl;
+	__le32		bth;
+	__le32		ct;
+	__le32		cte;
+	struct gce	entry[0];
+};
+
+struct enetc_cbd {
+	union{
+		struct {
+			__le32	addr[2];
+			union {
+				__le32	opt[4];
+				struct tgs_gcl_conf	gcl_conf;
+			};
+		};	/* Long format */
+		__le32 data[6];
+	};
+	__le16 index;
+	__le16 length;
+	u8 cmd;
+	u8 cls;
+	u8 _res;
+	u8 status_flags;
+};
+
+/* port time gating control register */
+#define ENETC_QBV_PTGCR_OFFSET		0x11a00
+#define ENETC_QBV_TGE			BIT(31)
+#define ENETC_QBV_TGPE			BIT(30)
+
+/* Port time gating capability register */
+#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
+#define ENETC_QBV_MAX_GCL_LEN_MASK	GENMASK(15, 0)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
new file mode 100644
index 000000000000..9ce983c00201
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2019 NXP */
+
+#include "enetc.h"
+
+#include <net/pkt_sched.h>
+
+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+{
+	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
+		& ENETC_QBV_MAX_GCL_LEN_MASK;
+}
+
+static int enetc_setup_taprio(struct net_device *ndev,
+			      struct tc_taprio_qopt_offload *admin_conf)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_cbd cbd = {.cmd = 0};
+	struct tgs_gcl_conf *gcl_config;
+	struct tgs_gcl_data *gcl_data;
+	struct gce *gce;
+	dma_addr_t dma;
+	u16 data_size;
+	u16 gcl_len;
+	u32 tge;
+	int err;
+	int i;
+
+	if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
+		return -EINVAL;
+	gcl_len = admin_conf->num_entries;
+
+	tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
+	if (!admin_conf->enable) {
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 tge & (~ENETC_QBV_TGE));
+		return 0;
+	}
+
+	if (admin_conf->cycle_time > (u32)~0 ||
+	    admin_conf->cycle_time_extension > (u32)~0)
+		return -EINVAL;
+
+	/* Configure the (administrative) gate control list using the
+	 * control BD descriptor.
+	 */
+	gcl_config = &cbd.gcl_conf;
+
+	data_size = struct_size(gcl_data, entry, gcl_len);
+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+	if (!gcl_data)
+		return -ENOMEM;
+
+	gce = (struct gce *)(gcl_data + 1);
+
+	/* Set all gates open as default */
+	gcl_config->atc = 0xff;
+	gcl_config->acl_len = cpu_to_le16(gcl_len);
+
+	if (!admin_conf->base_time) {
+		gcl_data->btl =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
+		gcl_data->bth =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
+	} else {
+		gcl_data->btl =
+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
+		gcl_data->bth =
+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
+	}
+
+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
+
+	for (i = 0; i < gcl_len; i++) {
+		struct tc_taprio_sched_entry *temp_entry;
+		struct gce *temp_gce = gce + i;
+
+		temp_entry = &admin_conf->entries[i];
+
+		temp_gce->gate = (u8)temp_entry->gate_mask;
+		temp_gce->period = cpu_to_le32(temp_entry->interval);
+	}
+
+	cbd.length = cpu_to_le16(data_size);
+	cbd.status_flags = 0;
+
+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+			     data_size, DMA_TO_DEVICE);
+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+		kfree(gcl_data);
+		return -ENOMEM;
+	}
+
+	cbd.addr[0] = lower_32_bits(dma);
+	cbd.addr[1] = upper_32_bits(dma);
+	cbd.cls = BDCR_CMD_PORT_GCL;
+	cbd.status_flags = 0;
+
+	enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+		 tge & (~ENETC_QBV_TGE));
+
+	usleep_range(10, 20);
+
+	enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+		 tge | ENETC_QBV_TGE);
+
+	err = enetc_send_cmd(priv->si, &cbd);
+	if (err)
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 tge & (~ENETC_QBV_TGE));
+
+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
+	kfree(gcl_data);
+
+	return err;
+}
+
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
+{
+	struct tc_taprio_qopt_offload *taprio = type_data;
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < priv->num_tx_rings; i++)
+		enetc_set_bdr_prio(&priv->si->hw,
+				   priv->tx_ring[i]->index,
+				   taprio->enable ? i : 0);
+
+	return enetc_setup_taprio(ndev, taprio);
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [v3,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-14  5:12       ` [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
@ 2019-11-14  5:12         ` Po Liu
  2019-11-15  3:33           ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-14 18:51         ` [v3,net-next, " Ivan Khoronzhuk
  1 sibling, 1 reply; 36+ messages in thread
From: Po Liu @ 2019-11-14  5:12 UTC (permalink / raw)
  To: Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC has a register PSPEED to indicate the link speed of hardware.
It is need to update accordingly. PSPEED field needs to be updated
with the port speed for QBV scheduling purposes. Or else there is
chance for gate slot not free by frame taking the MAC if PSPEED and
phy speed not match. So update PSPEED when link adjust. This is
implement by the adjust_link.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c  | 13 +++++--
 drivers/net/ethernet/freescale/enetc/enetc.h  |  8 +++++
 .../net/ethernet/freescale/enetc/enetc_hw.h   |  5 +++
 .../net/ethernet/freescale/enetc/enetc_pf.c   |  3 ++
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 34 +++++++++++++++++++
 5 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index d58dbc2c4270..f6b00c68451b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -742,9 +742,14 @@ void enetc_get_si_caps(struct enetc_si *si)
 	si->num_rss = 0;
 	val = enetc_rd(hw, ENETC_SIPCAPR0);
 	if (val & ENETC_SIPCAPR0_RSS) {
-		val = enetc_rd(hw, ENETC_SIRSSCAPR);
-		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val);
+		u32 rss;
+
+		rss = enetc_rd(hw, ENETC_SIRSSCAPR);
+		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
 	}
+
+	if (val & ENETC_SIPCAPR0_QBV)
+		si->hw_features |= ENETC_SI_F_QBV;
 }
 
 static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
@@ -1314,8 +1319,12 @@ static void enetc_disable_interrupts(struct enetc_ndev_priv *priv)
 
 static void adjust_link(struct net_device *ndev)
 {
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct phy_device *phydev = ndev->phydev;
 
+	if (priv->active_offloads & ENETC_F_QBV)
+		enetc_sched_speed_set(ndev);
+
 	phy_print_status(phydev);
 }
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 8ca2f97050c8..89f23156f330 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -118,6 +118,8 @@ enum enetc_errata {
 	ENETC_ERR_UCMCSWP	= BIT(2),
 };
 
+#define ENETC_SI_F_QBV BIT(0)
+
 /* PCI IEP device data */
 struct enetc_si {
 	struct pci_dev *pdev;
@@ -133,6 +135,7 @@ struct enetc_si {
 	int num_fs_entries;
 	int num_rss; /* number of RSS buckets */
 	unsigned short pad;
+	int hw_features;
 };
 
 #define ENETC_SI_ALIGN	32
@@ -173,6 +176,7 @@ struct enetc_cls_rule {
 enum enetc_active_offloads {
 	ENETC_F_RX_TSTAMP	= BIT(0),
 	ENETC_F_TX_TSTAMP	= BIT(1),
+	ENETC_F_QBV             = BIT(2),
 };
 
 struct enetc_ndev_priv {
@@ -188,6 +192,8 @@ struct enetc_ndev_priv {
 	u16 msg_enable;
 	int active_offloads;
 
+	u32 speed; /* store speed for compare update pspeed */
+
 	struct enetc_bdr *tx_ring[16];
 	struct enetc_bdr *rx_ring[16];
 
@@ -248,6 +254,8 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
 
 #ifdef CONFIG_FSL_ENETC_QOS
 int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+void enetc_sched_speed_set(struct net_device *ndev);
 #else
 #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+#define enetc_sched_speed_set(ndev) (void)0
 #endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index df6b35dc3534..924ddb6d358a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -149,6 +149,11 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PORT_BASE		0x10000
 #define ENETC_PMR		0x0000
 #define ENETC_PMR_EN	GENMASK(18, 16)
+#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
+#define ENETC_PMR_PSPEED_10M	0
+#define ENETC_PMR_PSPEED_100M	BIT(8)
+#define ENETC_PMR_PSPEED_1000M	BIT(9)
+#define ENETC_PMR_PSPEED_2500M	BIT(10)
 #define ENETC_PSR		0x0004 /* RO */
 #define ENETC_PSIPMR		0x0018
 #define ENETC_PSIPMR_SET_UP(n)	BIT(n) /* n = SI index */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 7da79b816416..e7482d483b28 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -742,6 +742,9 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 
 	ndev->priv_flags |= IFF_UNICAST_FLT;
 
+	if (si->hw_features & ENETC_SI_F_QBV)
+		priv->active_offloads |= ENETC_F_QBV;
+
 	/* pick up primary MAC address from SI */
 	enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
 }
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index 9ce983c00201..f804da639dd3 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -11,6 +11,40 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
 		& ENETC_QBV_MAX_GCL_LEN_MASK;
 }
 
+void enetc_sched_speed_set(struct net_device *ndev)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct phy_device *phydev = ndev->phydev;
+	u32 old_speed = priv->speed;
+	u32 speed, pspeed;
+
+	if (phydev->speed == old_speed)
+		return;
+
+	speed = phydev->speed;
+	switch (speed) {
+	case SPEED_1000:
+		pspeed = ENETC_PMR_PSPEED_1000M;
+		break;
+	case SPEED_2500:
+		pspeed = ENETC_PMR_PSPEED_2500M;
+		break;
+	case SPEED_100:
+		pspeed = ENETC_PMR_PSPEED_100M;
+		break;
+	case SPEED_10:
+	default:
+		pspeed = ENETC_PMR_PSPEED_10M;
+		netdev_err(ndev, "Qbv PSPEED set speed link down.\n");
+	}
+
+	priv->speed = speed;
+	enetc_port_wr(&priv->si->hw, ENETC_PMR,
+		      (enetc_port_rd(&priv->si->hw, ENETC_PMR)
+		      & (~ENETC_PMR_PSPEED_MASK))
+		      | pspeed);
+}
+
 static int enetc_setup_taprio(struct net_device *ndev,
 			      struct tc_taprio_qopt_offload *admin_conf)
 {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-14  5:12       ` [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-14  5:12         ` [v3,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-14 18:51         ` Ivan Khoronzhuk
  2019-11-15  2:37           ` [EXT] " Po Liu
  1 sibling, 1 reply; 36+ messages in thread
From: Ivan Khoronzhuk @ 2019-11-14 18:51 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Thu, Nov 14, 2019 at 05:12:30AM +0000, Po Liu wrote:
>ENETC supports in hardware for time-based egress shaping according
>to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
>hardware offload method qdisc tc-taprio method.
>Also update cbdr writeback to up level since control bd ring may
>writeback data to control bd ring.
>
>Signed-off-by: Po Liu <Po.Liu@nxp.com>
>Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
>Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
>---
>changes:
>v2:
>- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
>  configurations will result in link errors.
>  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
>  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
>  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
>  tsn feature, or else, return not support.
>v3:
>- fix the compiling vf module failure issue:
>  ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
>  ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
>- remove defines not used in this patch
>- fix hardware endian issue
>- make the qbv set code more rubust with some error condition may occur.
>
> drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
> drivers/net/ethernet/freescale/enetc/Makefile |   2 +
> drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
> .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> .../net/ethernet/freescale/enetc/enetc_hw.h   |  84 ++++++++---
> .../net/ethernet/freescale/enetc/enetc_qos.c  | 134 ++++++++++++++++++
> 7 files changed, 239 insertions(+), 22 deletions(-)
> create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
>
>diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
>index c219587bd334..491659fe3e35 100644
>--- a/drivers/net/ethernet/freescale/enetc/Kconfig
>+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
>@@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING
> 	  allocation has not been supported and it is too expensive to use
> 	  extended RX BDs if timestamping is not used, this option enables
> 	  extended RX BDs in order to support hardware timestamping.
>+
>+config FSL_ENETC_QOS
>+	bool "ENETC hardware Time-sensitive Network support"
>+	depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
>+	help
>+	  There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
>+	  /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
>+	  enable/disable from user space via Qos commands(tc). In the kernel
>+	  side, it can be loaded by Qos driver. Currently, it is only support
>+	  taprio(802.1Qbv).
>diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
>index d200c27c3bf6..d0db33e5b6b7 100644
>--- a/drivers/net/ethernet/freescale/enetc/Makefile
>+++ b/drivers/net/ethernet/freescale/enetc/Makefile
>@@ -5,9 +5,11 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
> obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
> fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
> fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
>+fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
>
> obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
> fsl-enetc-vf-y := enetc_vf.o $(common-objs)
>+fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
>
> obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o
> fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
>index 3e8f9819f08c..d58dbc2c4270 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc.c
>+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
>@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
> 	return 0;
> }
>
>-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>-		   void *type_data)
>+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
> {
> 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> 	struct tc_mqprio_qopt *mqprio = type_data;
>@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> 	u8 num_tc;
> 	int i;
>
>-	if (type != TC_SETUP_QDISC_MQPRIO)
>-		return -EOPNOTSUPP;
>-
> 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
> 	num_tc = mqprio->num_tc;
>
>@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> 	return 0;
> }
>
>+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>+		   void *type_data)
>+{
>+	switch (type) {
>+	case TC_SETUP_QDISC_MQPRIO:
>+		return enetc_setup_tc_mqprio(ndev, type_data);
>+	case TC_SETUP_QDISC_TAPRIO:
>+		return enetc_setup_tc_taprio(ndev, type_data);
>+	default:
>+		return -EOPNOTSUPP;
>+	}
>+}
>+
> struct net_device_stats *enetc_get_stats(struct net_device *ndev)
> {
> 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
>index 541b4e2073fe..8ca2f97050c8 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc.h
>+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
>@@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
> void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
> int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
> int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
>+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
>+
>+#ifdef CONFIG_FSL_ENETC_QOS
>+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
>+#else
>+#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
>+#endif
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>index de466b71bf8f..201cbc362e33 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
> 		r->bd_count;
> }
>
>-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
>+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> {
> 	struct enetc_cbdr *ring = &si->cbd_ring;
> 	int timeout = ENETC_CBDR_TIMEOUT;
>@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> 	if (!timeout)
> 		return -EBUSY;
>
>+	/* CBD may writeback data, feedback up level */
>+	*cbd = *dest_cbd;
>+
> 	enetc_clean_cbdr(si);
>
> 	return 0;
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>index 88276299f447..df6b35dc3534 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>@@ -18,6 +18,7 @@
> #define ENETC_SICTR0	0x18
> #define ENETC_SICTR1	0x1c
> #define ENETC_SIPCAPR0	0x20
>+#define ENETC_SIPCAPR0_QBV	BIT(4)
> #define ENETC_SIPCAPR0_RSS	BIT(8)
> #define ENETC_SIPCAPR1	0x24
> #define ENETC_SITGTGR	0x30
>@@ -440,22 +441,6 @@ union enetc_rx_bd {
> #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
> #define ENETC_MAX_NUM_VFS	2
>
>-struct enetc_cbd {
>-	union {
>-		struct {
>-			__le32 addr[2];
>-			__le32 opt[4];
>-		};
>-		__le32 data[6];
>-	};
>-	__le16 index;
>-	__le16 length;
>-	u8 cmd;
>-	u8 cls;
>-	u8 _res;
>-	u8 status_flags;
>-};
>-
> #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
> #define ENETC_CBD_STATUS_MASK	0xf
>
>@@ -554,3 +539,70 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
> 	val |= ENETC_TBMR_SET_PRIO(prio);
> 	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
> }
>+
>+enum bdcr_cmd_class {
>+	BDCR_CMD_UNSPEC = 0,
>+	BDCR_CMD_MAC_FILTER,
>+	BDCR_CMD_VLAN_FILTER,
>+	BDCR_CMD_RSS,
>+	BDCR_CMD_RFS,
>+	BDCR_CMD_PORT_GCL,
>+	BDCR_CMD_RECV_CLASSIFIER,
>+	__BDCR_CMD_MAX_LEN,
>+	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
>+};
>+
>+/* class 5, command 0 */
>+struct tgs_gcl_conf {
>+	u8	atc;	/* init gate value */
>+	u8	res[7];
>+	struct {
>+		u8	res1[4];
>+		__le16	acl_len;
>+		u8	res2[2];
>+	};
>+};
>+
>+/* gate control list entry */
>+struct gce {
>+	__le32	period;
>+	u8	gate;
>+	u8	res[3];
>+};
>+
>+/* tgs_gcl_conf address point to this data space */
>+struct tgs_gcl_data {
>+	__le32		btl;
>+	__le32		bth;
>+	__le32		ct;
>+	__le32		cte;
>+	struct gce	entry[0];
>+};
>+
>+struct enetc_cbd {
>+	union{
>+		struct {
>+			__le32	addr[2];
>+			union {
>+				__le32	opt[4];
>+				struct tgs_gcl_conf	gcl_conf;
>+			};
>+		};	/* Long format */
>+		__le32 data[6];
>+	};
>+	__le16 index;
>+	__le16 length;
>+	u8 cmd;
>+	u8 cls;
>+	u8 _res;
>+	u8 status_flags;
>+};
>+
>+/* port time gating control register */
>+#define ENETC_QBV_PTGCR_OFFSET		0x11a00
>+#define ENETC_QBV_TGE			BIT(31)
>+#define ENETC_QBV_TGPE			BIT(30)
>+
>+/* Port time gating capability register */
>+#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
>+#define ENETC_QBV_MAX_GCL_LEN_MASK	GENMASK(15, 0)
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
>new file mode 100644
>index 000000000000..9ce983c00201
>--- /dev/null
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
>@@ -0,0 +1,134 @@
>+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
>+/* Copyright 2019 NXP */
>+
>+#include "enetc.h"
>+
>+#include <net/pkt_sched.h>
>+
>+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
>+{
>+	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
>+		& ENETC_QBV_MAX_GCL_LEN_MASK;
>+}
>+
>+static int enetc_setup_taprio(struct net_device *ndev,
>+			      struct tc_taprio_qopt_offload *admin_conf)
>+{
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	struct enetc_cbd cbd = {.cmd = 0};
>+	struct tgs_gcl_conf *gcl_config;
>+	struct tgs_gcl_data *gcl_data;
>+	struct gce *gce;
>+	dma_addr_t dma;
>+	u16 data_size;
>+	u16 gcl_len;
>+	u32 tge;
>+	int err;
>+	int i;
>+
>+	if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
>+		return -EINVAL;
>+	gcl_len = admin_conf->num_entries;
>+
>+	tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
>+	if (!admin_conf->enable) {
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 tge & (~ENETC_QBV_TGE));
>+		return 0;
>+	}
>+
>+	if (admin_conf->cycle_time > (u32)~0 ||
>+	    admin_conf->cycle_time_extension > (u32)~0)
>+		return -EINVAL;

U32_MAX?

>+
>+	/* Configure the (administrative) gate control list using the
>+	 * control BD descriptor.
>+	 */
>+	gcl_config = &cbd.gcl_conf;
>+
>+	data_size = struct_size(gcl_data, entry, gcl_len);
>+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
>+	if (!gcl_data)
>+		return -ENOMEM;
>+
>+	gce = (struct gce *)(gcl_data + 1);
>+
>+	/* Set all gates open as default */
>+	gcl_config->atc = 0xff;
>+	gcl_config->acl_len = cpu_to_le16(gcl_len);
>+
>+	if (!admin_conf->base_time) {
>+		gcl_data->btl =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
>+		gcl_data->bth =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
>+	} else {
>+		gcl_data->btl =
>+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
>+		gcl_data->bth =
>+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
>+	}
>+
>+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
>+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
>+
>+	for (i = 0; i < gcl_len; i++) {
>+		struct tc_taprio_sched_entry *temp_entry;
>+		struct gce *temp_gce = gce + i;
>+
>+		temp_entry = &admin_conf->entries[i];
>+
>+		temp_gce->gate = (u8)temp_entry->gate_mask;
>+		temp_gce->period = cpu_to_le32(temp_entry->interval);
>+	}
>+
>+	cbd.length = cpu_to_le16(data_size);
>+	cbd.status_flags = 0;
>+
>+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
>+			     data_size, DMA_TO_DEVICE);
>+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
>+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
>+		kfree(gcl_data);
>+		return -ENOMEM;
>+	}
>+
>+	cbd.addr[0] = lower_32_bits(dma);
>+	cbd.addr[1] = upper_32_bits(dma);
>+	cbd.cls = BDCR_CMD_PORT_GCL;
>+	cbd.status_flags = 0;
>+
>+	enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
>+		 tge & (~ENETC_QBV_TGE));

Sorry, but, please, before sending new version, be sure you understand what
should be changed.

Let's back to IEEE Std 802.1Q

Do you know what means cycle time extension that is programmed here.
And why needed admin and oper configurations, and their base times?

It's needed to not stop active oper configuration (that actually this
function do), so that it's active till new one, that is admin, will
be able to replace it.

If user wants to stop it, and then load new one, he has to do it
himself. But, when some configuration is active - that is OPER at the
moment - and user requests w/o stopping it new configuration in some
new admin base time, the oper stay active till this admin base time,
then dropped in hw.

What this code do, it's in hidden way, stop oper configuration at
the time of configuration and no matter which admit base time is.

That's definitely wrong. Just look how sw version works.
And why all this admin/oper headache exists in IEEE Std 802.1Q
exactly for this reason.

So, if oper configuration exists at the moment of calling taprio
configuration and no way to apply new on in some future time
(admin base time), the code should say to user:

Please, stop prev. oper configuration - then prog new one.

The taprio interface is common and can't be treated differently
depending on hw.

Hope it's clean.

>+
>+	usleep_range(10, 20);
>+
>+	enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
>+		 tge | ENETC_QBV_TGE);
>+
>+	err = enetc_send_cmd(priv->si, &cbd);
>+	if (err)
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 tge & (~ENETC_QBV_TGE));
>+
>+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
>+	kfree(gcl_data);
>+
>+	return err;
>+}
>+
>+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
>+{
>+	struct tc_taprio_qopt_offload *taprio = type_data;
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	int i;
>+
>+	for (i = 0; i < priv->num_tx_rings; i++)
>+		enetc_set_bdr_prio(&priv->si->hw,
>+				   priv->tx_ring[i]->index,
>+				   taprio->enable ? i : 0);

Again, you should restore  enetc_set_bdr_prio
if below enetc_setup_taprio() fails.

>+
>+	return enetc_setup_taprio(ndev, taprio);
>+}
>-- 
>2.17.1
>

-- 
Regards,
Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [EXT] Re: [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-14 18:51         ` [v3,net-next, " Ivan Khoronzhuk
@ 2019-11-15  2:37           ` Po Liu
  0 siblings, 0 replies; 36+ messages in thread
From: Po Liu @ 2019-11-15  2:37 UTC (permalink / raw)
  To: Ivan Khoronzhuk
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li




Br,
Po Liu

> -----Original Message-----
> From: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
> Sent: 2019年11月15日 2:51
> To: Po Liu <po.liu@nxp.com>
> Cc: Claudiu Manoil <claudiu.manoil@nxp.com>; davem@davemloft.net; linux-
> kernel@vger.kernel.org; netdev@vger.kernel.org; vinicius.gomes@intel.com;
> Vladimir Oltean <vladimir.oltean@nxp.com>; Alexandru Marginean
> <alexandru.marginean@nxp.com>; Xiaoliang Yang
> <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu
> <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li
> <leoyang.li@nxp.com>
> Subject: [EXT] Re: [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler
> via tc-taprio offload
> 
> Caution: EXT Email
> 
> On Thu, Nov 14, 2019 at 05:12:30AM +0000, Po Liu wrote:
> >ENETC supports in hardware for time-based egress shaping according to
> >IEEE 802.1Qbv. This patch implement the Qbv enablement by the hardware
> >offload method qdisc tc-taprio method.
> >Also update cbdr writeback to up level since control bd ring may
> >writeback data to control bd ring.
> >
> >Signed-off-by: Po Liu <Po.Liu@nxp.com>
> >Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> >Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> >---
> >changes:
> >v2:
> >- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
> >  configurations will result in link errors.
> >  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
> >  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
> >  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
> >  tsn feature, or else, return not support.
> >v3:
> >- fix the compiling vf module failure issue:
> >  ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-
> enetc-vf.ko] undefined!
> >  ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-
> enetc-vf.ko] undefined!
> >- remove defines not used in this patch
> >- fix hardware endian issue
> >- make the qbv set code more rubust with some error condition may occur.
> >
> > drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
> > drivers/net/ethernet/freescale/enetc/Makefile |   2 +
> > drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> > drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
> > .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> > .../net/ethernet/freescale/enetc/enetc_hw.h   |  84 ++++++++---
> > .../net/ethernet/freescale/enetc/enetc_qos.c  | 134 ++++++++++++++++++
> > 7 files changed, 239 insertions(+), 22 deletions(-) create mode 100644
> > drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >
> >diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig
> >b/drivers/net/ethernet/freescale/enetc/Kconfig
> >index c219587bd334..491659fe3e35 100644
> >--- a/drivers/net/ethernet/freescale/enetc/Kconfig
> >+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
> >@@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING
> >         allocation has not been supported and it is too expensive to use
> >         extended RX BDs if timestamping is not used, this option enables
> >         extended RX BDs in order to support hardware timestamping.
> >+
> >+config FSL_ENETC_QOS
> >+      bool "ENETC hardware Time-sensitive Network support"
> >+      depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
> >+      help
> >+        There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
> >+        /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
> >+        enable/disable from user space via Qos commands(tc). In the kernel
> >+        side, it can be loaded by Qos driver. Currently, it is only support
> >+        taprio(802.1Qbv).
> >diff --git a/drivers/net/ethernet/freescale/enetc/Makefile
> >b/drivers/net/ethernet/freescale/enetc/Makefile
> >index d200c27c3bf6..d0db33e5b6b7 100644
> >--- a/drivers/net/ethernet/freescale/enetc/Makefile
> >+++ b/drivers/net/ethernet/freescale/enetc/Makefile
> >@@ -5,9 +5,11 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
> > obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o  fsl-enetc-y := enetc_pf.o
> >enetc_mdio.o $(common-objs)
> > fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
> >+fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
> >
> > obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o fsl-enetc-vf-y :=
> > enetc_vf.o $(common-objs)
> >+fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
> >
> > obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o  fsl-enetc-mdio-y :=
> >enetc_pci_mdio.o enetc_mdio.o diff --git
> >a/drivers/net/ethernet/freescale/enetc/enetc.c
> >b/drivers/net/ethernet/freescale/enetc/enetc.c
> >index 3e8f9819f08c..d58dbc2c4270 100644
> >--- a/drivers/net/ethernet/freescale/enetc/enetc.c
> >+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> >@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
> >       return 0;
> > }
> >
> >-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> >-                 void *type_data)
> >+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
> > {
> >       struct enetc_ndev_priv *priv = netdev_priv(ndev);
> >       struct tc_mqprio_qopt *mqprio = type_data; @@ -1436,9 +1435,6 @@
> >int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> >       u8 num_tc;
> >       int i;
> >
> >-      if (type != TC_SETUP_QDISC_MQPRIO)
> >-              return -EOPNOTSUPP;
> >-
> >       mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
> >       num_tc = mqprio->num_tc;
> >
> >@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum
> tc_setup_type type,
> >       return 0;
> > }
> >
> >+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> >+                 void *type_data)
> >+{
> >+      switch (type) {
> >+      case TC_SETUP_QDISC_MQPRIO:
> >+              return enetc_setup_tc_mqprio(ndev, type_data);
> >+      case TC_SETUP_QDISC_TAPRIO:
> >+              return enetc_setup_tc_taprio(ndev, type_data);
> >+      default:
> >+              return -EOPNOTSUPP;
> >+      }
> >+}
> >+
> > struct net_device_stats *enetc_get_stats(struct net_device *ndev)  {
> >       struct enetc_ndev_priv *priv = netdev_priv(ndev); diff --git
> >a/drivers/net/ethernet/freescale/enetc/enetc.h
> >b/drivers/net/ethernet/freescale/enetc/enetc.h
> >index 541b4e2073fe..8ca2f97050c8 100644
> >--- a/drivers/net/ethernet/freescale/enetc/enetc.h
> >+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
> >@@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *si, struct
> >enetc_cmd_rfse *rfse,  void enetc_set_rss_key(struct enetc_hw *hw,
> >const u8 *bytes);  int enetc_get_rss_table(struct enetc_si *si, u32
> >*table, int count);  int enetc_set_rss_table(struct enetc_si *si, const
> >u32 *table, int count);
> >+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
> >+
> >+#ifdef CONFIG_FSL_ENETC_QOS
> >+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
> >+#else #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
> >+#endif
> >diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> >b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> >index de466b71bf8f..201cbc362e33 100644
> >--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> >+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> >@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
> >               r->bd_count;
> > }
> >
> >-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> >+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> > {
> >       struct enetc_cbdr *ring = &si->cbd_ring;
> >       int timeout = ENETC_CBDR_TIMEOUT; @@ -66,6 +66,9 @@ static int
> >enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> >       if (!timeout)
> >               return -EBUSY;
> >
> >+      /* CBD may writeback data, feedback up level */
> >+      *cbd = *dest_cbd;
> >+
> >       enetc_clean_cbdr(si);
> >
> >       return 0;
> >diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> >b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> >index 88276299f447..df6b35dc3534 100644
> >--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> >+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> >@@ -18,6 +18,7 @@
> > #define ENETC_SICTR0  0x18
> > #define ENETC_SICTR1  0x1c
> > #define ENETC_SIPCAPR0        0x20
> >+#define ENETC_SIPCAPR0_QBV    BIT(4)
> > #define ENETC_SIPCAPR0_RSS    BIT(8)
> > #define ENETC_SIPCAPR1        0x24
> > #define ENETC_SITGTGR 0x30
> >@@ -440,22 +441,6 @@ union enetc_rx_bd {
> > #define EMETC_MAC_ADDR_FILT_RES       3 /* # of reserved entries at the
> beginning */
> > #define ENETC_MAX_NUM_VFS     2
> >
> >-struct enetc_cbd {
> >-      union {
> >-              struct {
> >-                      __le32 addr[2];
> >-                      __le32 opt[4];
> >-              };
> >-              __le32 data[6];
> >-      };
> >-      __le16 index;
> >-      __le16 length;
> >-      u8 cmd;
> >-      u8 cls;
> >-      u8 _res;
> >-      u8 status_flags;
> >-};
> >-
> > #define ENETC_CBD_FLAGS_SF    BIT(7) /* short format */
> > #define ENETC_CBD_STATUS_MASK 0xf
> >
> >@@ -554,3 +539,70 @@ static inline void enetc_set_bdr_prio(struct
> enetc_hw *hw, int bdr_idx,
> >       val |= ENETC_TBMR_SET_PRIO(prio);
> >       enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);  }
> >+
> >+enum bdcr_cmd_class {
> >+      BDCR_CMD_UNSPEC = 0,
> >+      BDCR_CMD_MAC_FILTER,
> >+      BDCR_CMD_VLAN_FILTER,
> >+      BDCR_CMD_RSS,
> >+      BDCR_CMD_RFS,
> >+      BDCR_CMD_PORT_GCL,
> >+      BDCR_CMD_RECV_CLASSIFIER,
> >+      __BDCR_CMD_MAX_LEN,
> >+      BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1, };
> >+
> >+/* class 5, command 0 */
> >+struct tgs_gcl_conf {
> >+      u8      atc;    /* init gate value */
> >+      u8      res[7];
> >+      struct {
> >+              u8      res1[4];
> >+              __le16  acl_len;
> >+              u8      res2[2];
> >+      };
> >+};
> >+
> >+/* gate control list entry */
> >+struct gce {
> >+      __le32  period;
> >+      u8      gate;
> >+      u8      res[3];
> >+};
> >+
> >+/* tgs_gcl_conf address point to this data space */ struct
> >+tgs_gcl_data {
> >+      __le32          btl;
> >+      __le32          bth;
> >+      __le32          ct;
> >+      __le32          cte;
> >+      struct gce      entry[0];
> >+};
> >+
> >+struct enetc_cbd {
> >+      union{
> >+              struct {
> >+                      __le32  addr[2];
> >+                      union {
> >+                              __le32  opt[4];
> >+                              struct tgs_gcl_conf     gcl_conf;
> >+                      };
> >+              };      /* Long format */
> >+              __le32 data[6];
> >+      };
> >+      __le16 index;
> >+      __le16 length;
> >+      u8 cmd;
> >+      u8 cls;
> >+      u8 _res;
> >+      u8 status_flags;
> >+};
> >+
> >+/* port time gating control register */
> >+#define ENETC_QBV_PTGCR_OFFSET                0x11a00
> >+#define ENETC_QBV_TGE                 BIT(31)
> >+#define ENETC_QBV_TGPE                        BIT(30)
> >+
> >+/* Port time gating capability register */
> >+#define ENETC_QBV_PTGCAPR_OFFSET      0x11a08
> >+#define ENETC_QBV_MAX_GCL_LEN_MASK    GENMASK(15, 0)
> >diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >new file mode 100644
> >index 000000000000..9ce983c00201
> >--- /dev/null
> >+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
> >@@ -0,0 +1,134 @@
> >+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
> >+/* Copyright 2019 NXP */
> >+
> >+#include "enetc.h"
> >+
> >+#include <net/pkt_sched.h>
> >+
> >+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw) {
> >+      return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
> >+              & ENETC_QBV_MAX_GCL_LEN_MASK; }
> >+
> >+static int enetc_setup_taprio(struct net_device *ndev,
> >+                            struct tc_taprio_qopt_offload *admin_conf)
> >+{
> >+      struct enetc_ndev_priv *priv = netdev_priv(ndev);
> >+      struct enetc_cbd cbd = {.cmd = 0};
> >+      struct tgs_gcl_conf *gcl_config;
> >+      struct tgs_gcl_data *gcl_data;
> >+      struct gce *gce;
> >+      dma_addr_t dma;
> >+      u16 data_size;
> >+      u16 gcl_len;
> >+      u32 tge;
> >+      int err;
> >+      int i;
> >+
> >+      if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
> >+              return -EINVAL;
> >+      gcl_len = admin_conf->num_entries;
> >+
> >+      tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
> >+      if (!admin_conf->enable) {
> >+              enetc_wr(&priv->si->hw,
> >+                       ENETC_QBV_PTGCR_OFFSET,
> >+                       tge & (~ENETC_QBV_TGE));
> >+              return 0;
> >+      }
> >+
> >+      if (admin_conf->cycle_time > (u32)~0 ||
> >+          admin_conf->cycle_time_extension > (u32)~0)
> >+              return -EINVAL;
> 
> U32_MAX?
> 
> >+
> >+      /* Configure the (administrative) gate control list using the
> >+       * control BD descriptor.
> >+       */
> >+      gcl_config = &cbd.gcl_conf;
> >+
> >+      data_size = struct_size(gcl_data, entry, gcl_len);
> >+      gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
> >+      if (!gcl_data)
> >+              return -ENOMEM;
> >+
> >+      gce = (struct gce *)(gcl_data + 1);
> >+
> >+      /* Set all gates open as default */
> >+      gcl_config->atc = 0xff;
> >+      gcl_config->acl_len = cpu_to_le16(gcl_len);
> >+
> >+      if (!admin_conf->base_time) {
> >+              gcl_data->btl =
> >+                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
> >+              gcl_data->bth =
> >+                      cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
> >+      } else {
> >+              gcl_data->btl =
> >+                      cpu_to_le32(lower_32_bits(admin_conf->base_time));
> >+              gcl_data->bth =
> >+                      cpu_to_le32(upper_32_bits(admin_conf->base_time));
> >+      }
> >+
> >+      gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
> >+      gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
> >+
> >+      for (i = 0; i < gcl_len; i++) {
> >+              struct tc_taprio_sched_entry *temp_entry;
> >+              struct gce *temp_gce = gce + i;
> >+
> >+              temp_entry = &admin_conf->entries[i];
> >+
> >+              temp_gce->gate = (u8)temp_entry->gate_mask;
> >+              temp_gce->period = cpu_to_le32(temp_entry->interval);
> >+      }
> >+
> >+      cbd.length = cpu_to_le16(data_size);
> >+      cbd.status_flags = 0;
> >+
> >+      dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
> >+                           data_size, DMA_TO_DEVICE);
> >+      if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
> >+              netdev_err(priv->si->ndev, "DMA mapping failed!\n");
> >+              kfree(gcl_data);
> >+              return -ENOMEM;
> >+      }
> >+
> >+      cbd.addr[0] = lower_32_bits(dma);
> >+      cbd.addr[1] = upper_32_bits(dma);
> >+      cbd.cls = BDCR_CMD_PORT_GCL;
> >+      cbd.status_flags = 0;
> >+
> >+      enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
> >+               tge & (~ENETC_QBV_TGE));
> 
> Sorry, but, please, before sending new version, be sure you understand what
> should be changed.
> 
> Let's back to IEEE Std 802.1Q
> 
> Do you know what means cycle time extension that is programmed here.
> And why needed admin and oper configurations, and their base times?
> 
> It's needed to not stop active oper configuration (that actually this function do),
> so that it's active till new one, that is admin, will be able to replace it.
> 
> If user wants to stop it, and then load new one, he has to do it himself. But,
> when some configuration is active - that is OPER at the moment - and user
> requests w/o stopping it new configuration in some new admin base time, the
> oper stay active till this admin base time, then dropped in hw.
> 
> What this code do, it's in hidden way, stop oper configuration at the time of
> configuration and no matter which admit base time is.

I am definitely know the spec in the Qbv. Here is hardware errata which I have mentioned in previous feedback in v2.
 
> 
> That's definitely wrong. Just look how sw version works.
> And why all this admin/oper headache exists in IEEE Std 802.1Q exactly for this
> reason.
> 
> So, if oper configuration exists at the moment of calling taprio configuration
> and no way to apply new on in some future time (admin base time), the code
> should say to user:
> 
> Please, stop prev. oper configuration - then prog new one.
> 
> The taprio interface is common and can't be treated differently depending on
> hw.
> 
> Hope it's clean.
> 
> >+
> >+      usleep_range(10, 20);
> >+
> >+      enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
> >+               tge | ENETC_QBV_TGE);
> >+
> >+      err = enetc_send_cmd(priv->si, &cbd);
> >+      if (err)
> >+              enetc_wr(&priv->si->hw,
> >+                       ENETC_QBV_PTGCR_OFFSET,
> >+                       tge & (~ENETC_QBV_TGE));
> >+
> >+      dma_unmap_single(&priv->si->pdev->dev, dma, data_size,
> DMA_TO_DEVICE);
> >+      kfree(gcl_data);
> >+
> >+      return err;
> >+}
> >+
> >+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) {
> >+      struct tc_taprio_qopt_offload *taprio = type_data;
> >+      struct enetc_ndev_priv *priv = netdev_priv(ndev);
> >+      int i;
> >+
> >+      for (i = 0; i < priv->num_tx_rings; i++)
> >+              enetc_set_bdr_prio(&priv->si->hw,
> >+                                 priv->tx_ring[i]->index,
> >+                                 taprio->enable ? i : 0);
> 
> Again, you should restore  enetc_set_bdr_prio if below enetc_setup_taprio()
> fails.
> 
> >+
> >+      return enetc_setup_taprio(ndev, taprio); }
> >--
> >2.17.1
> >
> 
> --
> Regards,
> Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-14  5:12         ` [v3,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-15  3:33           ` Po Liu
  2019-11-15  3:33             ` [v4,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
                               ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Po Liu @ 2019-11-15  3:33 UTC (permalink / raw)
  To: ivan.khoronzhuk, Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC supports in hardware for time-based egress shaping according
to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
hardware offload method qdisc tc-taprio method.
Also update cbdr writeback to up level since control bd ring may
writeback data to control bd ring.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
---
changes:
v2:
- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
  configurations will result in link errors.
  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
  tsn feature, or else, return not support.
v3:
- fix the compiling vf module failure issue:
  ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
  ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
- remove defines not used in this patch
- fix hardware endian issue
- make the qbv set code more rubust with some error condition may occur.
v4:
- delete hardware qbv disable before enable it
- fix when enetc_setup_taprio() return error condition, restore priority
set.

 drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
 drivers/net/ethernet/freescale/enetc/Makefile |   2 +
 drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
 drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
 .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
 .../net/ethernet/freescale/enetc/enetc_hw.h   |  84 +++++++++--
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 138 ++++++++++++++++++
 7 files changed, 243 insertions(+), 22 deletions(-)
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c

diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index c219587bd334..491659fe3e35 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING
 	  allocation has not been supported and it is too expensive to use
 	  extended RX BDs if timestamping is not used, this option enables
 	  extended RX BDs in order to support hardware timestamping.
+
+config FSL_ENETC_QOS
+	bool "ENETC hardware Time-sensitive Network support"
+	depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
+	help
+	  There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
+	  /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
+	  enable/disable from user space via Qos commands(tc). In the kernel
+	  side, it can be loaded by Qos driver. Currently, it is only support
+	  taprio(802.1Qbv).
diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index d200c27c3bf6..d0db33e5b6b7 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -5,9 +5,11 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
 obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
 fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
 fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
+fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
 
 obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
 fsl-enetc-vf-y := enetc_vf.o $(common-objs)
+fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
 
 obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o
 fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 3e8f9819f08c..d58dbc2c4270 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
 	return 0;
 }
 
-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
-		   void *type_data)
+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct tc_mqprio_qopt *mqprio = type_data;
@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	u8 num_tc;
 	int i;
 
-	if (type != TC_SETUP_QDISC_MQPRIO)
-		return -EOPNOTSUPP;
-
 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
 	num_tc = mqprio->num_tc;
 
@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	return 0;
 }
 
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+		   void *type_data)
+{
+	switch (type) {
+	case TC_SETUP_QDISC_MQPRIO:
+		return enetc_setup_tc_mqprio(ndev, type_data);
+	case TC_SETUP_QDISC_TAPRIO:
+		return enetc_setup_tc_taprio(ndev, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 struct net_device_stats *enetc_get_stats(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 541b4e2073fe..8ca2f97050c8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
 void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
+
+#ifdef CONFIG_FSL_ENETC_QOS
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+#else
+#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+#endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
index de466b71bf8f..201cbc362e33 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
 		r->bd_count;
 }
 
-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 {
 	struct enetc_cbdr *ring = &si->cbd_ring;
 	int timeout = ENETC_CBDR_TIMEOUT;
@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
 	if (!timeout)
 		return -EBUSY;
 
+	/* CBD may writeback data, feedback up level */
+	*cbd = *dest_cbd;
+
 	enetc_clean_cbdr(si);
 
 	return 0;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 88276299f447..df6b35dc3534 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -18,6 +18,7 @@
 #define ENETC_SICTR0	0x18
 #define ENETC_SICTR1	0x1c
 #define ENETC_SIPCAPR0	0x20
+#define ENETC_SIPCAPR0_QBV	BIT(4)
 #define ENETC_SIPCAPR0_RSS	BIT(8)
 #define ENETC_SIPCAPR1	0x24
 #define ENETC_SITGTGR	0x30
@@ -440,22 +441,6 @@ union enetc_rx_bd {
 #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
 #define ENETC_MAX_NUM_VFS	2
 
-struct enetc_cbd {
-	union {
-		struct {
-			__le32 addr[2];
-			__le32 opt[4];
-		};
-		__le32 data[6];
-	};
-	__le16 index;
-	__le16 length;
-	u8 cmd;
-	u8 cls;
-	u8 _res;
-	u8 status_flags;
-};
-
 #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
 #define ENETC_CBD_STATUS_MASK	0xf
 
@@ -554,3 +539,70 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
 	val |= ENETC_TBMR_SET_PRIO(prio);
 	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
 }
+
+enum bdcr_cmd_class {
+	BDCR_CMD_UNSPEC = 0,
+	BDCR_CMD_MAC_FILTER,
+	BDCR_CMD_VLAN_FILTER,
+	BDCR_CMD_RSS,
+	BDCR_CMD_RFS,
+	BDCR_CMD_PORT_GCL,
+	BDCR_CMD_RECV_CLASSIFIER,
+	__BDCR_CMD_MAX_LEN,
+	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
+};
+
+/* class 5, command 0 */
+struct tgs_gcl_conf {
+	u8	atc;	/* init gate value */
+	u8	res[7];
+	struct {
+		u8	res1[4];
+		__le16	acl_len;
+		u8	res2[2];
+	};
+};
+
+/* gate control list entry */
+struct gce {
+	__le32	period;
+	u8	gate;
+	u8	res[3];
+};
+
+/* tgs_gcl_conf address point to this data space */
+struct tgs_gcl_data {
+	__le32		btl;
+	__le32		bth;
+	__le32		ct;
+	__le32		cte;
+	struct gce	entry[0];
+};
+
+struct enetc_cbd {
+	union{
+		struct {
+			__le32	addr[2];
+			union {
+				__le32	opt[4];
+				struct tgs_gcl_conf	gcl_conf;
+			};
+		};	/* Long format */
+		__le32 data[6];
+	};
+	__le16 index;
+	__le16 length;
+	u8 cmd;
+	u8 cls;
+	u8 _res;
+	u8 status_flags;
+};
+
+/* port time gating control register */
+#define ENETC_QBV_PTGCR_OFFSET		0x11a00
+#define ENETC_QBV_TGE			BIT(31)
+#define ENETC_QBV_TGPE			BIT(30)
+
+/* Port time gating capability register */
+#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
+#define ENETC_QBV_MAX_GCL_LEN_MASK	GENMASK(15, 0)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
new file mode 100644
index 000000000000..84c2ab98fae9
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2019 NXP */
+
+#include "enetc.h"
+
+#include <net/pkt_sched.h>
+
+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+{
+	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
+		& ENETC_QBV_MAX_GCL_LEN_MASK;
+}
+
+static int enetc_setup_taprio(struct net_device *ndev,
+			      struct tc_taprio_qopt_offload *admin_conf)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_cbd cbd = {.cmd = 0};
+	struct tgs_gcl_conf *gcl_config;
+	struct tgs_gcl_data *gcl_data;
+	struct gce *gce;
+	dma_addr_t dma;
+	u16 data_size;
+	u16 gcl_len;
+	u32 tge;
+	int err;
+	int i;
+
+	if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
+		return -EINVAL;
+	gcl_len = admin_conf->num_entries;
+
+	tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
+	if (!admin_conf->enable) {
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 tge & (~ENETC_QBV_TGE));
+		return 0;
+	}
+
+	if (admin_conf->cycle_time > U32_MAX ||
+	    admin_conf->cycle_time_extension > U32_MAX)
+		return -EINVAL;
+
+	/* Configure the (administrative) gate control list using the
+	 * control BD descriptor.
+	 */
+	gcl_config = &cbd.gcl_conf;
+
+	data_size = struct_size(gcl_data, entry, gcl_len);
+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
+	if (!gcl_data)
+		return -ENOMEM;
+
+	gce = (struct gce *)(gcl_data + 1);
+
+	/* Set all gates open as default */
+	gcl_config->atc = 0xff;
+	gcl_config->acl_len = cpu_to_le16(gcl_len);
+
+	if (!admin_conf->base_time) {
+		gcl_data->btl =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
+		gcl_data->bth =
+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
+	} else {
+		gcl_data->btl =
+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
+		gcl_data->bth =
+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
+	}
+
+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
+
+	for (i = 0; i < gcl_len; i++) {
+		struct tc_taprio_sched_entry *temp_entry;
+		struct gce *temp_gce = gce + i;
+
+		temp_entry = &admin_conf->entries[i];
+
+		temp_gce->gate = (u8)temp_entry->gate_mask;
+		temp_gce->period = cpu_to_le32(temp_entry->interval);
+	}
+
+	cbd.length = cpu_to_le16(data_size);
+	cbd.status_flags = 0;
+
+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
+			     data_size, DMA_TO_DEVICE);
+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
+		kfree(gcl_data);
+		return -ENOMEM;
+	}
+
+	cbd.addr[0] = lower_32_bits(dma);
+	cbd.addr[1] = upper_32_bits(dma);
+	cbd.cls = BDCR_CMD_PORT_GCL;
+	cbd.status_flags = 0;
+
+	enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
+		 tge | ENETC_QBV_TGE);
+
+	err = enetc_send_cmd(priv->si, &cbd);
+	if (err)
+		enetc_wr(&priv->si->hw,
+			 ENETC_QBV_PTGCR_OFFSET,
+			 tge & (~ENETC_QBV_TGE));
+
+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
+	kfree(gcl_data);
+
+	return err;
+}
+
+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
+{
+	struct tc_taprio_qopt_offload *taprio = type_data;
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	int err;
+	int i;
+
+	for (i = 0; i < priv->num_tx_rings; i++)
+		enetc_set_bdr_prio(&priv->si->hw,
+				   priv->tx_ring[i]->index,
+				   taprio->enable ? i : 0);
+
+	err = enetc_setup_taprio(ndev, taprio);
+
+	if (err)
+		for (i = 0; i < priv->num_tx_rings; i++)
+			enetc_set_bdr_prio(&priv->si->hw,
+					   priv->tx_ring[i]->index,
+					   taprio->enable ? 0 : i);
+
+	return err;
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [v4,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-15  3:33           ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
@ 2019-11-15  3:33             ` Po Liu
  2019-11-16 20:49               ` David Miller
  2019-11-15 15:20             ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Ivan Khoronzhuk
  2019-11-16 20:49             ` David Miller
  2 siblings, 1 reply; 36+ messages in thread
From: Po Liu @ 2019-11-15  3:33 UTC (permalink / raw)
  To: ivan.khoronzhuk, Claudiu Manoil, davem, linux-kernel, netdev
  Cc: vinicius.gomes, Po Liu, Vladimir Oltean, Alexandru Marginean,
	Xiaoliang Yang, Roy Zang, Mingkai Hu, Jerry Huang, Leo Li,
	Po Liu

ENETC has a register PSPEED to indicate the link speed of hardware.
It is need to update accordingly. PSPEED field needs to be updated
with the port speed for QBV scheduling purposes. Or else there is
chance for gate slot not free by frame taking the MAC if PSPEED and
phy speed not match. So update PSPEED when link adjust. This is
implement by the adjust_link.

Signed-off-by: Po Liu <Po.Liu@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c  | 13 +++++--
 drivers/net/ethernet/freescale/enetc/enetc.h  |  8 +++++
 .../net/ethernet/freescale/enetc/enetc_hw.h   |  5 +++
 .../net/ethernet/freescale/enetc/enetc_pf.c   |  3 ++
 .../net/ethernet/freescale/enetc/enetc_qos.c  | 34 +++++++++++++++++++
 5 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index d58dbc2c4270..f6b00c68451b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -742,9 +742,14 @@ void enetc_get_si_caps(struct enetc_si *si)
 	si->num_rss = 0;
 	val = enetc_rd(hw, ENETC_SIPCAPR0);
 	if (val & ENETC_SIPCAPR0_RSS) {
-		val = enetc_rd(hw, ENETC_SIRSSCAPR);
-		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val);
+		u32 rss;
+
+		rss = enetc_rd(hw, ENETC_SIRSSCAPR);
+		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
 	}
+
+	if (val & ENETC_SIPCAPR0_QBV)
+		si->hw_features |= ENETC_SI_F_QBV;
 }
 
 static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
@@ -1314,8 +1319,12 @@ static void enetc_disable_interrupts(struct enetc_ndev_priv *priv)
 
 static void adjust_link(struct net_device *ndev)
 {
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct phy_device *phydev = ndev->phydev;
 
+	if (priv->active_offloads & ENETC_F_QBV)
+		enetc_sched_speed_set(ndev);
+
 	phy_print_status(phydev);
 }
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 8ca2f97050c8..89f23156f330 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -118,6 +118,8 @@ enum enetc_errata {
 	ENETC_ERR_UCMCSWP	= BIT(2),
 };
 
+#define ENETC_SI_F_QBV BIT(0)
+
 /* PCI IEP device data */
 struct enetc_si {
 	struct pci_dev *pdev;
@@ -133,6 +135,7 @@ struct enetc_si {
 	int num_fs_entries;
 	int num_rss; /* number of RSS buckets */
 	unsigned short pad;
+	int hw_features;
 };
 
 #define ENETC_SI_ALIGN	32
@@ -173,6 +176,7 @@ struct enetc_cls_rule {
 enum enetc_active_offloads {
 	ENETC_F_RX_TSTAMP	= BIT(0),
 	ENETC_F_TX_TSTAMP	= BIT(1),
+	ENETC_F_QBV             = BIT(2),
 };
 
 struct enetc_ndev_priv {
@@ -188,6 +192,8 @@ struct enetc_ndev_priv {
 	u16 msg_enable;
 	int active_offloads;
 
+	u32 speed; /* store speed for compare update pspeed */
+
 	struct enetc_bdr *tx_ring[16];
 	struct enetc_bdr *rx_ring[16];
 
@@ -248,6 +254,8 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
 
 #ifdef CONFIG_FSL_ENETC_QOS
 int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
+void enetc_sched_speed_set(struct net_device *ndev);
 #else
 #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+#define enetc_sched_speed_set(ndev) (void)0
 #endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index df6b35dc3534..924ddb6d358a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -149,6 +149,11 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PORT_BASE		0x10000
 #define ENETC_PMR		0x0000
 #define ENETC_PMR_EN	GENMASK(18, 16)
+#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8)
+#define ENETC_PMR_PSPEED_10M	0
+#define ENETC_PMR_PSPEED_100M	BIT(8)
+#define ENETC_PMR_PSPEED_1000M	BIT(9)
+#define ENETC_PMR_PSPEED_2500M	BIT(10)
 #define ENETC_PSR		0x0004 /* RO */
 #define ENETC_PSIPMR		0x0018
 #define ENETC_PSIPMR_SET_UP(n)	BIT(n) /* n = SI index */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 7da79b816416..e7482d483b28 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -742,6 +742,9 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 
 	ndev->priv_flags |= IFF_UNICAST_FLT;
 
+	if (si->hw_features & ENETC_SI_F_QBV)
+		priv->active_offloads |= ENETC_F_QBV;
+
 	/* pick up primary MAC address from SI */
 	enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
 }
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index 84c2ab98fae9..66a3da61ca16 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -11,6 +11,40 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
 		& ENETC_QBV_MAX_GCL_LEN_MASK;
 }
 
+void enetc_sched_speed_set(struct net_device *ndev)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct phy_device *phydev = ndev->phydev;
+	u32 old_speed = priv->speed;
+	u32 speed, pspeed;
+
+	if (phydev->speed == old_speed)
+		return;
+
+	speed = phydev->speed;
+	switch (speed) {
+	case SPEED_1000:
+		pspeed = ENETC_PMR_PSPEED_1000M;
+		break;
+	case SPEED_2500:
+		pspeed = ENETC_PMR_PSPEED_2500M;
+		break;
+	case SPEED_100:
+		pspeed = ENETC_PMR_PSPEED_100M;
+		break;
+	case SPEED_10:
+	default:
+		pspeed = ENETC_PMR_PSPEED_10M;
+		netdev_err(ndev, "Qbv PSPEED set speed link down.\n");
+	}
+
+	priv->speed = speed;
+	enetc_port_wr(&priv->si->hw, ENETC_PMR,
+		      (enetc_port_rd(&priv->si->hw, ENETC_PMR)
+		      & (~ENETC_PMR_PSPEED_MASK))
+		      | pspeed);
+}
+
 static int enetc_setup_taprio(struct net_device *ndev,
 			      struct tc_taprio_qopt_offload *admin_conf)
 {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-15  3:33           ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-15  3:33             ` [v4,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-15 15:20             ` Ivan Khoronzhuk
  2019-11-16 20:49             ` David Miller
  2 siblings, 0 replies; 36+ messages in thread
From: Ivan Khoronzhuk @ 2019-11-15 15:20 UTC (permalink / raw)
  To: Po Liu
  Cc: Claudiu Manoil, davem, linux-kernel, netdev, vinicius.gomes,
	Vladimir Oltean, Alexandru Marginean, Xiaoliang Yang, Roy Zang,
	Mingkai Hu, Jerry Huang, Leo Li

On Fri, Nov 15, 2019 at 03:33:33AM +0000, Po Liu wrote:
>ENETC supports in hardware for time-based egress shaping according
>to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
>hardware offload method qdisc tc-taprio method.
>Also update cbdr writeback to up level since control bd ring may
>writeback data to control bd ring.
>
>Signed-off-by: Po Liu <Po.Liu@nxp.com>
>Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
>Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
>---
>changes:
>v2:
>- introduce a local define CONFIG_FSL_ENETC_QOS to fix the various
>  configurations will result in link errors.
>  Since the CONFIG_NET_SCH_TAPRIO depends on many Qos configs. Not
>  to use it directly in driver. Add it to CONFIG_FSL_ENETC_QOS depends
>  on list, so only CONFIG_NET_SCH_TAPRIO enabled, user can enable this
>  tsn feature, or else, return not support.
>v3:
>- fix the compiling vf module failure issue:
>  ERROR: "enetc_sched_speed_set" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
>  ERROR: "enetc_setup_tc_taprio" [drivers/net/ethernet/freescale/enetc/fsl-enetc-vf.ko] undefined!
>- remove defines not used in this patch
>- fix hardware endian issue
>- make the qbv set code more rubust with some error condition may occur.
>v4:
>- delete hardware qbv disable before enable it
>- fix when enetc_setup_taprio() return error condition, restore priority
>set.
>
> drivers/net/ethernet/freescale/enetc/Kconfig  |  10 ++
> drivers/net/ethernet/freescale/enetc/Makefile |   2 +
> drivers/net/ethernet/freescale/enetc/enetc.c  |  19 ++-
> drivers/net/ethernet/freescale/enetc/enetc.h  |   7 +
> .../net/ethernet/freescale/enetc/enetc_cbdr.c |   5 +-
> .../net/ethernet/freescale/enetc/enetc_hw.h   |  84 +++++++++--
> .../net/ethernet/freescale/enetc/enetc_qos.c  | 138 ++++++++++++++++++
> 7 files changed, 243 insertions(+), 22 deletions(-)
> create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c
>
>diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
>index c219587bd334..491659fe3e35 100644
>--- a/drivers/net/ethernet/freescale/enetc/Kconfig
>+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
>@@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING
> 	  allocation has not been supported and it is too expensive to use
> 	  extended RX BDs if timestamping is not used, this option enables
> 	  extended RX BDs in order to support hardware timestamping.
>+
>+config FSL_ENETC_QOS
>+	bool "ENETC hardware Time-sensitive Network support"
>+	depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
>+	help
>+	  There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
>+	  /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
>+	  enable/disable from user space via Qos commands(tc). In the kernel
>+	  side, it can be loaded by Qos driver. Currently, it is only support
>+	  taprio(802.1Qbv).
>diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
>index d200c27c3bf6..d0db33e5b6b7 100644
>--- a/drivers/net/ethernet/freescale/enetc/Makefile
>+++ b/drivers/net/ethernet/freescale/enetc/Makefile
>@@ -5,9 +5,11 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o
> obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
> fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs)
> fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
>+fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
>
> obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
> fsl-enetc-vf-y := enetc_vf.o $(common-objs)
>+fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
>
> obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o
> fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
>index 3e8f9819f08c..d58dbc2c4270 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc.c
>+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
>@@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev)
> 	return 0;
> }
>
>-int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>-		   void *type_data)
>+int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
> {
> 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> 	struct tc_mqprio_qopt *mqprio = type_data;
>@@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> 	u8 num_tc;
> 	int i;
>
>-	if (type != TC_SETUP_QDISC_MQPRIO)
>-		return -EOPNOTSUPP;
>-
> 	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
> 	num_tc = mqprio->num_tc;
>
>@@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
> 	return 0;
> }
>
>+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
>+		   void *type_data)
>+{
>+	switch (type) {
>+	case TC_SETUP_QDISC_MQPRIO:
>+		return enetc_setup_tc_mqprio(ndev, type_data);
>+	case TC_SETUP_QDISC_TAPRIO:
>+		return enetc_setup_tc_taprio(ndev, type_data);
>+	default:
>+		return -EOPNOTSUPP;
>+	}
>+}
>+
> struct net_device_stats *enetc_get_stats(struct net_device *ndev)
> {
> 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
>index 541b4e2073fe..8ca2f97050c8 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc.h
>+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
>@@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
> void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
> int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
> int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
>+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
>+
>+#ifdef CONFIG_FSL_ENETC_QOS
>+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
>+#else
>+#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
>+#endif
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>index de466b71bf8f..201cbc362e33 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
>@@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r)
> 		r->bd_count;
> }
>
>-static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
>+int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> {
> 	struct enetc_cbdr *ring = &si->cbd_ring;
> 	int timeout = ENETC_CBDR_TIMEOUT;
>@@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
> 	if (!timeout)
> 		return -EBUSY;
>
>+	/* CBD may writeback data, feedback up level */
>+	*cbd = *dest_cbd;
>+
> 	enetc_clean_cbdr(si);
>
> 	return 0;
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>index 88276299f447..df6b35dc3534 100644
>--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
>@@ -18,6 +18,7 @@
> #define ENETC_SICTR0	0x18
> #define ENETC_SICTR1	0x1c
> #define ENETC_SIPCAPR0	0x20
>+#define ENETC_SIPCAPR0_QBV	BIT(4)
> #define ENETC_SIPCAPR0_RSS	BIT(8)
> #define ENETC_SIPCAPR1	0x24
> #define ENETC_SITGTGR	0x30
>@@ -440,22 +441,6 @@ union enetc_rx_bd {
> #define EMETC_MAC_ADDR_FILT_RES	3 /* # of reserved entries at the beginning */
> #define ENETC_MAX_NUM_VFS	2
>
>-struct enetc_cbd {
>-	union {
>-		struct {
>-			__le32 addr[2];
>-			__le32 opt[4];
>-		};
>-		__le32 data[6];
>-	};
>-	__le16 index;
>-	__le16 length;
>-	u8 cmd;
>-	u8 cls;
>-	u8 _res;
>-	u8 status_flags;
>-};
>-
> #define ENETC_CBD_FLAGS_SF	BIT(7) /* short format */
> #define ENETC_CBD_STATUS_MASK	0xf
>
>@@ -554,3 +539,70 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
> 	val |= ENETC_TBMR_SET_PRIO(prio);
> 	enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
> }
>+
>+enum bdcr_cmd_class {
>+	BDCR_CMD_UNSPEC = 0,
>+	BDCR_CMD_MAC_FILTER,
>+	BDCR_CMD_VLAN_FILTER,
>+	BDCR_CMD_RSS,
>+	BDCR_CMD_RFS,
>+	BDCR_CMD_PORT_GCL,
>+	BDCR_CMD_RECV_CLASSIFIER,
>+	__BDCR_CMD_MAX_LEN,
>+	BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1,
>+};
>+
>+/* class 5, command 0 */
>+struct tgs_gcl_conf {
>+	u8	atc;	/* init gate value */
>+	u8	res[7];
>+	struct {
>+		u8	res1[4];
>+		__le16	acl_len;
>+		u8	res2[2];
>+	};
>+};
>+
>+/* gate control list entry */
>+struct gce {
>+	__le32	period;
>+	u8	gate;
>+	u8	res[3];
>+};
>+
>+/* tgs_gcl_conf address point to this data space */
>+struct tgs_gcl_data {
>+	__le32		btl;
>+	__le32		bth;
>+	__le32		ct;
>+	__le32		cte;
>+	struct gce	entry[0];
>+};
>+
>+struct enetc_cbd {
>+	union{
>+		struct {
>+			__le32	addr[2];
>+			union {
>+				__le32	opt[4];
>+				struct tgs_gcl_conf	gcl_conf;
>+			};
>+		};	/* Long format */
>+		__le32 data[6];
>+	};
>+	__le16 index;
>+	__le16 length;
>+	u8 cmd;
>+	u8 cls;
>+	u8 _res;
>+	u8 status_flags;
>+};
>+
>+/* port time gating control register */
>+#define ENETC_QBV_PTGCR_OFFSET		0x11a00
>+#define ENETC_QBV_TGE			BIT(31)
>+#define ENETC_QBV_TGPE			BIT(30)
>+
>+/* Port time gating capability register */
>+#define ENETC_QBV_PTGCAPR_OFFSET	0x11a08
>+#define ENETC_QBV_MAX_GCL_LEN_MASK	GENMASK(15, 0)
>diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
>new file mode 100644
>index 000000000000..84c2ab98fae9
>--- /dev/null
>+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
>@@ -0,0 +1,138 @@
>+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
>+/* Copyright 2019 NXP */
>+
>+#include "enetc.h"
>+
>+#include <net/pkt_sched.h>
>+
>+static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
>+{
>+	return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET)
>+		& ENETC_QBV_MAX_GCL_LEN_MASK;
>+}
>+
>+static int enetc_setup_taprio(struct net_device *ndev,
>+			      struct tc_taprio_qopt_offload *admin_conf)
>+{
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	struct enetc_cbd cbd = {.cmd = 0};
>+	struct tgs_gcl_conf *gcl_config;
>+	struct tgs_gcl_data *gcl_data;
>+	struct gce *gce;
>+	dma_addr_t dma;
>+	u16 data_size;
>+	u16 gcl_len;
>+	u32 tge;
>+	int err;
>+	int i;
>+
>+	if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw))
>+		return -EINVAL;
>+	gcl_len = admin_conf->num_entries;
>+
>+	tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET);
>+	if (!admin_conf->enable) {
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 tge & (~ENETC_QBV_TGE));
>+		return 0;

Answer on comment in v3,
Problem not in errata - problem in w/a.
If it gets to unknown state - better restart it, but not silently.
I see dropped the reset in this version, you probably better know the errata
w/a.

but I've expected it to be reseted by asking user explicitly to do this if oper
cycle is present as it's probably not what is expected, if no oper state then
reset and start as it was.

Now the reset is removed from configuration, even if there is no oper state.
Probably it's not good. But you better know.

What actually the problem to save variable like priv->qbv_enabled and use it for
making appropriate decision?

JFI, you can use also link on allocated configuration from taprio with API from
taprio:

taprio_offload_free(taprio);
taprio_offload_get(taprio);

preventing taprio struct from to be freed.

And use taprio pointer as a boolen instead of priv->qbv_enabled.
Kind of:

if (priv->taprio)
	taprio_offload_free(priv->taprio);

priv->taprio = taprio->enable ? taprio_offload_get(taprio) :
				NULL;

So you have saved conf settings (seems like you don't need, but that's for now)
and at the same time a key to read enable/disable state.

>+	}
>+
>+	if (admin_conf->cycle_time > U32_MAX ||
>+	    admin_conf->cycle_time_extension > U32_MAX)
>+		return -EINVAL;
>+
>+	/* Configure the (administrative) gate control list using the
>+	 * control BD descriptor.
>+	 */
>+	gcl_config = &cbd.gcl_conf;
>+
>+	data_size = struct_size(gcl_data, entry, gcl_len);
>+	gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
>+	if (!gcl_data)
>+		return -ENOMEM;
>+
>+	gce = (struct gce *)(gcl_data + 1);
>+
>+	/* Set all gates open as default */
>+	gcl_config->atc = 0xff;
>+	gcl_config->acl_len = cpu_to_le16(gcl_len);
>+
>+	if (!admin_conf->base_time) {
>+		gcl_data->btl =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0));
>+		gcl_data->bth =
>+			cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1));
>+	} else {
>+		gcl_data->btl =
>+			cpu_to_le32(lower_32_bits(admin_conf->base_time));
>+		gcl_data->bth =
>+			cpu_to_le32(upper_32_bits(admin_conf->base_time));
>+	}
>+
>+	gcl_data->ct = cpu_to_le32(admin_conf->cycle_time);
>+	gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension);
>+
>+	for (i = 0; i < gcl_len; i++) {
>+		struct tc_taprio_sched_entry *temp_entry;
>+		struct gce *temp_gce = gce + i;
>+
>+		temp_entry = &admin_conf->entries[i];
>+
>+		temp_gce->gate = (u8)temp_entry->gate_mask;
>+		temp_gce->period = cpu_to_le32(temp_entry->interval);
>+	}
>+
>+	cbd.length = cpu_to_le16(data_size);
>+	cbd.status_flags = 0;
>+
>+	dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
>+			     data_size, DMA_TO_DEVICE);
>+	if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
>+		netdev_err(priv->si->ndev, "DMA mapping failed!\n");
>+		kfree(gcl_data);
>+		return -ENOMEM;
>+	}
>+
>+	cbd.addr[0] = lower_32_bits(dma);
>+	cbd.addr[1] = upper_32_bits(dma);
>+	cbd.cls = BDCR_CMD_PORT_GCL;
>+	cbd.status_flags = 0;
>+
>+	enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET,
>+		 tge | ENETC_QBV_TGE);
>+
>+	err = enetc_send_cmd(priv->si, &cbd);
>+	if (err)
>+		enetc_wr(&priv->si->hw,
>+			 ENETC_QBV_PTGCR_OFFSET,
>+			 tge & (~ENETC_QBV_TGE));
>+
>+	dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
>+	kfree(gcl_data);
>+
>+	return err;
>+}
>+
>+int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data)
>+{
>+	struct tc_taprio_qopt_offload *taprio = type_data;
>+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>+	int err;
>+	int i;
>+
>+	for (i = 0; i < priv->num_tx_rings; i++)
>+		enetc_set_bdr_prio(&priv->si->hw,
>+				   priv->tx_ring[i]->index,
>+				   taprio->enable ? i : 0);
>+
>+	err = enetc_setup_taprio(ndev, taprio);
>+
>+	if (err)
>+		for (i = 0; i < priv->num_tx_rings; i++)
>+			enetc_set_bdr_prio(&priv->si->hw,
>+					   priv->tx_ring[i]->index,
>+					   taprio->enable ? 0 : i);
>+
>+	return err;
>+}
>-- 
>2.17.1
>

-- 
Regards,
Ivan Khoronzhuk

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload
  2019-11-15  3:33           ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
  2019-11-15  3:33             ` [v4,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
  2019-11-15 15:20             ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Ivan Khoronzhuk
@ 2019-11-16 20:49             ` David Miller
  2 siblings, 0 replies; 36+ messages in thread
From: David Miller @ 2019-11-16 20:49 UTC (permalink / raw)
  To: po.liu
  Cc: ivan.khoronzhuk, claudiu.manoil, linux-kernel, netdev,
	vinicius.gomes, vladimir.oltean, alexandru.marginean,
	xiaoliang.yang_1, roy.zang, mingkai.hu, jerry.huang, leoyang.li

From: Po Liu <po.liu@nxp.com>
Date: Fri, 15 Nov 2019 03:33:33 +0000

> ENETC supports in hardware for time-based egress shaping according
> to IEEE 802.1Qbv. This patch implement the Qbv enablement by the
> hardware offload method qdisc tc-taprio method.
> Also update cbdr writeback to up level since control bd ring may
> writeback data to control bd ring.
> 
> Signed-off-by: Po Liu <Po.Liu@nxp.com>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>

Applied.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [v4,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed
  2019-11-15  3:33             ` [v4,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
@ 2019-11-16 20:49               ` David Miller
  0 siblings, 0 replies; 36+ messages in thread
From: David Miller @ 2019-11-16 20:49 UTC (permalink / raw)
  To: po.liu
  Cc: ivan.khoronzhuk, claudiu.manoil, linux-kernel, netdev,
	vinicius.gomes, vladimir.oltean, alexandru.marginean,
	xiaoliang.yang_1, roy.zang, mingkai.hu, jerry.huang, leoyang.li

From: Po Liu <po.liu@nxp.com>
Date: Fri, 15 Nov 2019 03:33:41 +0000

> ENETC has a register PSPEED to indicate the link speed of hardware.
> It is need to update accordingly. PSPEED field needs to be updated
> with the port speed for QBV scheduling purposes. Or else there is
> chance for gate slot not free by frame taking the MAC if PSPEED and
> phy speed not match. So update PSPEED when link adjust. This is
> implement by the adjust_link.
> 
> Signed-off-by: Po Liu <Po.Liu@nxp.com>
> Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Applied.

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2019-11-16 20:49 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-11  4:41 [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
2019-11-11  4:41 ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
2019-11-12  8:42   ` [v2,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
2019-11-12  8:42     ` [v2,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
2019-11-12 18:57       ` David Miller
2019-11-14  5:12       ` [v3,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
2019-11-14  5:12         ` [v3,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
2019-11-15  3:33           ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Po Liu
2019-11-15  3:33             ` [v4,net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Po Liu
2019-11-16 20:49               ` David Miller
2019-11-15 15:20             ` [v4,net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload Ivan Khoronzhuk
2019-11-16 20:49             ` David Miller
2019-11-14 18:51         ` [v3,net-next, " Ivan Khoronzhuk
2019-11-15  2:37           ` [EXT] " Po Liu
2019-11-12 18:57     ` [v2,net-next, " David Miller
2019-11-12 21:10     ` Ivan Khoronzhuk
2019-11-13  3:45       ` [EXT] " Po Liu
2019-11-13 13:41         ` Ivan Khoronzhuk
2019-11-14  4:39           ` Po Liu
2019-11-12  9:41   ` [net-next, 2/2] enetc: update TSN Qbv PSPEED set according to adjust link speed Simon Horman
2019-11-12 19:59   ` kbuild test robot
2019-11-12  5:50 ` [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload David Miller
2019-11-12  6:48   ` [EXT] " Po Liu
2019-11-12  9:41 ` Simon Horman
2019-11-12 11:19   ` [EXT] " Po Liu
2019-11-12 11:54     ` Claudiu Manoil
2019-11-12 13:46       ` Simon Horman
2019-11-12 13:50     ` Simon Horman
2019-11-12 18:58   ` David Miller
2019-11-12 18:59     ` David Miller
2019-11-13  4:55       ` [EXT] " Po Liu
2019-11-12 12:31 ` kbuild test robot
2019-11-12 12:43 ` kbuild test robot
2019-11-12 16:03 ` Ivan Khoronzhuk
2019-11-12 22:57 ` [RFC PATCH] enetc: enetc_setup_tc_mqprio() can be static kbuild test robot
2019-11-12 22:57 ` [net-next, 1/2] enetc: Configure the Time-Aware Scheduler via tc-taprio offload kbuild test robot

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).