aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch231
1 files changed, 231 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch b/target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch
new file mode 100644
index 0000000000..fd89174d59
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch
@@ -0,0 +1,231 @@
+From 3426e5e4339f124f00eef8815b56a80481364550 Mon Sep 17 00:00:00 2001
+From: Po Liu <po.liu@nxp.com>
+Date: Mon, 25 Nov 2019 05:56:56 +0000
+Subject: [PATCH] enetc: add support Credit Based Shaper(CBS) for hardware
+ offload
+
+The ENETC hardware support the Credit Based Shaper(CBS) which part
+of the IEEE-802.1Qav. The CBS driver was loaded by the sch_cbs
+interface when set in the QOS in the kernel.
+
+Here is an example command to set 20Mbits bandwidth in 1Gbits port
+for taffic class 7:
+
+tc qdisc add dev eth0 root handle 1: mqprio \
+ num_tc 8 map 0 1 2 3 4 5 6 7 hw 1
+
+tc qdisc replace dev eth0 parent 1:8 cbs \
+ locredit -1470 hicredit 30 \
+ sendslope -980000 idleslope 20000 offload 1
+
+Signed-off-by: Po Liu <Po.Liu@nxp.com>
+Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
+Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/freescale/enetc/Kconfig | 4 +-
+ drivers/net/ethernet/freescale/enetc/enetc.c | 2 +
+ drivers/net/ethernet/freescale/enetc/enetc.h | 2 +
+ drivers/net/ethernet/freescale/enetc/enetc_hw.h | 4 +
+ drivers/net/ethernet/freescale/enetc/enetc_qos.c | 128 +++++++++++++++++++++++
+ 5 files changed, 138 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/enetc/Kconfig
++++ b/drivers/net/ethernet/freescale/enetc/Kconfig
+@@ -53,10 +53,10 @@ config FSL_ENETC_HW_TIMESTAMPING
+
+ config FSL_ENETC_QOS
+ bool "ENETC hardware Time-sensitive Network support"
+- depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
++ depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS)
+ 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).
++ taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
+--- a/drivers/net/ethernet/freescale/enetc/enetc.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc.c
+@@ -1524,6 +1524,8 @@ int enetc_setup_tc(struct net_device *nd
+ return enetc_setup_tc_mqprio(ndev, type_data);
+ case TC_SETUP_QDISC_TAPRIO:
+ return enetc_setup_tc_taprio(ndev, type_data);
++ case TC_SETUP_QDISC_CBS:
++ return enetc_setup_tc_cbs(ndev, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+--- a/drivers/net/ethernet/freescale/enetc/enetc.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc.h
+@@ -255,7 +255,9 @@ int enetc_send_cmd(struct enetc_si *si,
+ #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);
++int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
+ #else
+ #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
+ #define enetc_sched_speed_set(ndev) (void)0
++#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
+ #endif
+--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
++++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+@@ -185,6 +185,8 @@ enum enetc_bdr_type {TX, RX};
+ #define ENETC_PSICFGR0_SIVC(bmp) (((bmp) & 0xff) << 24) /* VLAN_TYPE */
+
+ #define ENETC_PTCCBSR0(n) (0x1110 + (n) * 8) /* n = 0 to 7*/
++#define ENETC_CBSE BIT(31)
++#define ENETC_CBS_BW_MASK GENMASK(6, 0)
+ #define ENETC_PTCCBSR1(n) (0x1114 + (n) * 8) /* n = 0 to 7*/
+ #define ENETC_RSSHASH_KEY_SIZE 40
+ #define ENETC_PRSSK(n) (0x1410 + (n) * 4) /* n = [0..9] */
+@@ -673,6 +675,8 @@ struct enetc_cbd {
+ u8 status_flags;
+ };
+
++#define ENETC_CLK 400000000ULL
++
+ /* port time gating control register */
+ #define ENETC_QBV_PTGCR_OFFSET 0x11a00
+ #define ENETC_QBV_TGE BIT(31)
+--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+@@ -4,6 +4,7 @@
+ #include "enetc.h"
+
+ #include <net/pkt_sched.h>
++#include <linux/math64.h>
+
+ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
+ {
+@@ -170,3 +171,130 @@ int enetc_setup_tc_taprio(struct net_dev
+
+ return err;
+ }
++
++static u32 enetc_get_cbs_enable(struct enetc_hw *hw, u8 tc)
++{
++ return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBSE;
++}
++
++static u8 enetc_get_cbs_bw(struct enetc_hw *hw, u8 tc)
++{
++ return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBS_BW_MASK;
++}
++
++int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
++{
++ struct enetc_ndev_priv *priv = netdev_priv(ndev);
++ struct tc_cbs_qopt_offload *cbs = type_data;
++ u32 port_transmit_rate = priv->speed;
++ u8 tc_nums = netdev_get_num_tc(ndev);
++ struct enetc_si *si = priv->si;
++ u32 hi_credit_bit, hi_credit_reg;
++ u32 max_interference_size;
++ u32 port_frame_max_size;
++ u32 tc_max_sized_frame;
++ u8 tc = cbs->queue;
++ u8 prio_top, prio_next;
++ int bw_sum = 0;
++ u8 bw;
++
++ prio_top = netdev_get_prio_tc_map(ndev, tc_nums - 1);
++ prio_next = netdev_get_prio_tc_map(ndev, tc_nums - 2);
++
++ /* Support highest prio and second prio tc in cbs mode */
++ if (tc != prio_top && tc != prio_next)
++ return -EOPNOTSUPP;
++
++ if (!cbs->enable) {
++ /* Make sure the other TC that are numerically
++ * lower than this TC have been disabled.
++ */
++ if (tc == prio_top &&
++ enetc_get_cbs_enable(&si->hw, prio_next)) {
++ dev_err(&ndev->dev,
++ "Disable TC%d before disable TC%d\n",
++ prio_next, tc);
++ return -EINVAL;
++ }
++
++ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0);
++ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0);
++
++ return 0;
++ }
++
++ if (cbs->idleslope - cbs->sendslope != port_transmit_rate * 1000L ||
++ cbs->idleslope < 0 || cbs->sendslope > 0)
++ return -EOPNOTSUPP;
++
++ port_frame_max_size = ndev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
++
++ bw = cbs->idleslope / (port_transmit_rate * 10UL);
++
++ /* Make sure the other TC that are numerically
++ * higher than this TC have been enabled.
++ */
++ if (tc == prio_next) {
++ if (!enetc_get_cbs_enable(&si->hw, prio_top)) {
++ dev_err(&ndev->dev,
++ "Enable TC%d first before enable TC%d\n",
++ prio_top, prio_next);
++ return -EINVAL;
++ }
++ bw_sum += enetc_get_cbs_bw(&si->hw, prio_top);
++ }
++
++ if (bw_sum + bw >= 100) {
++ dev_err(&ndev->dev,
++ "The sum of all CBS Bandwidth can't exceed 100\n");
++ return -EINVAL;
++ }
++
++ tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc));
++
++ /* For top prio TC, the max_interfrence_size is maxSizedFrame.
++ *
++ * For next prio TC, the max_interfrence_size is calculated as below:
++ *
++ * max_interference_size = M0 + Ma + Ra * M0 / (R0 - Ra)
++ *
++ * - RA: idleSlope for AVB Class A
++ * - R0: port transmit rate
++ * - M0: maximum sized frame for the port
++ * - MA: maximum sized frame for AVB Class A
++ */
++
++ if (tc == prio_top) {
++ max_interference_size = port_frame_max_size * 8;
++ } else {
++ u32 m0, ma, r0, ra;
++
++ m0 = port_frame_max_size * 8;
++ ma = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(prio_top)) * 8;
++ ra = enetc_get_cbs_bw(&si->hw, prio_top) *
++ port_transmit_rate * 10000ULL;
++ r0 = port_transmit_rate * 1000000ULL;
++ max_interference_size = m0 + ma +
++ (u32)div_u64((u64)ra * m0, r0 - ra);
++ }
++
++ /* hiCredit bits calculate by:
++ *
++ * maxSizedFrame * (idleSlope/portTxRate)
++ */
++ hi_credit_bit = max_interference_size * bw / 100;
++
++ /* hiCredit bits to hiCredit register need to calculated as:
++ *
++ * (enetClockFrequency / portTransmitRate) * 100
++ */
++ hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit,
++ port_transmit_rate * 1000000ULL);
++
++ enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit_reg);
++
++ /* Set bw register and enable this traffic class */
++ enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE);
++
++ return 0;
++}