mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 09:12:39 +00:00
2c81b16964
Ran update_kernel.sh in a fresh clone without any existing toolchains. Manually rebased: bcm27xx/950-0993-xhci-quirks-add-link-TRB-quirk-for-VL805.patch layerscape/701-net-0231-enetc-Use-DT-protocol-information-to-set-up-the-port.patch Build system: x86_64 Build-tested: ipq806x/R7800 Run-tested: ipq806x/R7800 No dmesg regressions, everything functional Signed-off-by: John Audia <graysky@archlinux.us> [remove accidental whitespace edit] Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
379 lines
11 KiB
Diff
379 lines
11 KiB
Diff
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
|
|
@@ -1422,8 +1422,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;
|
|
@@ -1431,9 +1430,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;
|
|
|
|
@@ -1478,6 +1474,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
|
|
@@ -249,3 +249,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
|
|
@@ -446,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
|
|
|
|
@@ -560,3 +545,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;
|
|
+}
|