mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-22 15:02:32 +00:00
76d1168d0d
Ran update_kernel.sh in a fresh clone without any existing toolchains.
No manual changes needed.
Build system: x86_64
Build-tested: bcm27xx/bcm2711
Signed-off-by: John Audia <graysky@archlinux.us>
(cherry-picked from commit 5d3a6fd970
)
232 lines
7.5 KiB
Diff
232 lines
7.5 KiB
Diff
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_PRSSCAPR 0x1404
|
|
@@ -679,6 +681,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;
|
|
+}
|