diff options
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.patch | 378 |
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; ++} |