aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch378
1 files changed, 378 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch b/target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch
new file mode 100644
index 0000000000..37ed557c32
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/701-net-0225-enetc-Configure-the-Time-Aware-Scheduler-via-tc-tapr.patch
@@ -0,0 +1,378 @@
+From 6ee2331a3a5627b062daf76aa5ed9f64fbbfa303 Mon Sep 17 00:00:00 2001
+From: Po Liu <po.liu@nxp.com>
+Date: Fri, 15 Nov 2019 03:33:33 +0000
+Subject: [PATCH] enetc: Configure the Time-Aware Scheduler via tc-taprio
+ offload
+
+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>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ 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 ++
+ drivers/net/ethernet/freescale/enetc/enetc_cbdr.c | 5 +-
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h | 84 ++++++++++---
+ drivers/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
+
+--- 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).
+--- 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 enet
+ 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
+--- 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 *nd
+ 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 *nd
+ 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);
+--- 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 *
+ 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
+--- 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
+ 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_s
+ if (!timeout)
+ return -EBUSY;
+
++ /* CBD may writeback data, feedback up level */
++ *cbd = *dest_cbd;
++
+ enetc_clean_cbdr(si);
+
+ return 0;
+--- 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(st
+ 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)
+--- /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;
++}