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