ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 701-net-0336-enetc-add-support-Credit-Based-Shaper-CBS-for-hardwa.patch
1 From 3426e5e4339f124f00eef8815b56a80481364550 Mon Sep 17 00:00:00 2001
2 From: Po Liu <po.liu@nxp.com>
3 Date: Mon, 25 Nov 2019 05:56:56 +0000
4 Subject: [PATCH] enetc: add support Credit Based Shaper(CBS) for hardware
5  offload
6
7 The ENETC hardware support the Credit Based Shaper(CBS) which part
8 of the IEEE-802.1Qav. The CBS driver was loaded by the sch_cbs
9 interface when set in the QOS in the kernel.
10
11 Here is an example command to set 20Mbits bandwidth in 1Gbits port
12 for taffic class 7:
13
14 tc qdisc add dev eth0 root handle 1: mqprio \
15            num_tc 8 map 0 1 2 3 4 5 6 7 hw 1
16
17 tc qdisc replace dev eth0 parent 1:8 cbs \
18            locredit -1470 hicredit 30 \
19            sendslope -980000 idleslope 20000 offload 1
20
21 Signed-off-by: Po Liu <Po.Liu@nxp.com>
22 Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
23 Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
24 Signed-off-by: David S. Miller <davem@davemloft.net>
25 ---
26  drivers/net/ethernet/freescale/enetc/Kconfig     |   4 +-
27  drivers/net/ethernet/freescale/enetc/enetc.c     |   2 +
28  drivers/net/ethernet/freescale/enetc/enetc.h     |   2 +
29  drivers/net/ethernet/freescale/enetc/enetc_hw.h  |   4 +
30  drivers/net/ethernet/freescale/enetc/enetc_qos.c | 128 +++++++++++++++++++++++
31  5 files changed, 138 insertions(+), 2 deletions(-)
32
33 --- a/drivers/net/ethernet/freescale/enetc/Kconfig
34 +++ b/drivers/net/ethernet/freescale/enetc/Kconfig
35 @@ -53,10 +53,10 @@ config FSL_ENETC_HW_TIMESTAMPING
36  
37  config FSL_ENETC_QOS
38         bool "ENETC hardware Time-sensitive Network support"
39 -       depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO
40 +       depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS)
41         help
42           There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci
43           /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set
44           enable/disable from user space via Qos commands(tc). In the kernel
45           side, it can be loaded by Qos driver. Currently, it is only support
46 -         taprio(802.1Qbv).
47 +         taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
48 --- a/drivers/net/ethernet/freescale/enetc/enetc.c
49 +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
50 @@ -1524,6 +1524,8 @@ int enetc_setup_tc(struct net_device *nd
51                 return enetc_setup_tc_mqprio(ndev, type_data);
52         case TC_SETUP_QDISC_TAPRIO:
53                 return enetc_setup_tc_taprio(ndev, type_data);
54 +       case TC_SETUP_QDISC_CBS:
55 +               return enetc_setup_tc_cbs(ndev, type_data);
56         default:
57                 return -EOPNOTSUPP;
58         }
59 --- a/drivers/net/ethernet/freescale/enetc/enetc.h
60 +++ b/drivers/net/ethernet/freescale/enetc/enetc.h
61 @@ -255,7 +255,9 @@ int enetc_send_cmd(struct enetc_si *si,
62  #ifdef CONFIG_FSL_ENETC_QOS
63  int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data);
64  void enetc_sched_speed_set(struct net_device *ndev);
65 +int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data);
66  #else
67  #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP
68  #define enetc_sched_speed_set(ndev) (void)0
69 +#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP
70  #endif
71 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
72 +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
73 @@ -185,6 +185,8 @@ enum enetc_bdr_type {TX, RX};
74  #define ENETC_PSICFGR0_SIVC(bmp)       (((bmp) & 0xff) << 24) /* VLAN_TYPE */
75  
76  #define ENETC_PTCCBSR0(n)      (0x1110 + (n) * 8) /* n = 0 to 7*/
77 +#define ENETC_CBSE             BIT(31)
78 +#define ENETC_CBS_BW_MASK      GENMASK(6, 0)
79  #define ENETC_PTCCBSR1(n)      (0x1114 + (n) * 8) /* n = 0 to 7*/
80  #define ENETC_RSSHASH_KEY_SIZE 40
81  #define ENETC_PRSSK(n)         (0x1410 + (n) * 4) /* n = [0..9] */
82 @@ -673,6 +675,8 @@ struct enetc_cbd {
83         u8 status_flags;
84  };
85  
86 +#define ENETC_CLK  400000000ULL
87 +
88  /* port time gating control register */
89  #define ENETC_QBV_PTGCR_OFFSET         0x11a00
90  #define ENETC_QBV_TGE                  BIT(31)
91 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
92 +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
93 @@ -4,6 +4,7 @@
94  #include "enetc.h"
95  
96  #include <net/pkt_sched.h>
97 +#include <linux/math64.h>
98  
99  static u16 enetc_get_max_gcl_len(struct enetc_hw *hw)
100  {
101 @@ -170,3 +171,130 @@ int enetc_setup_tc_taprio(struct net_dev
102  
103         return err;
104  }
105 +
106 +static u32 enetc_get_cbs_enable(struct enetc_hw *hw, u8 tc)
107 +{
108 +       return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBSE;
109 +}
110 +
111 +static u8 enetc_get_cbs_bw(struct enetc_hw *hw, u8 tc)
112 +{
113 +       return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBS_BW_MASK;
114 +}
115 +
116 +int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
117 +{
118 +       struct enetc_ndev_priv *priv = netdev_priv(ndev);
119 +       struct tc_cbs_qopt_offload *cbs = type_data;
120 +       u32 port_transmit_rate = priv->speed;
121 +       u8 tc_nums = netdev_get_num_tc(ndev);
122 +       struct enetc_si *si = priv->si;
123 +       u32 hi_credit_bit, hi_credit_reg;
124 +       u32 max_interference_size;
125 +       u32 port_frame_max_size;
126 +       u32 tc_max_sized_frame;
127 +       u8 tc = cbs->queue;
128 +       u8 prio_top, prio_next;
129 +       int bw_sum = 0;
130 +       u8 bw;
131 +
132 +       prio_top = netdev_get_prio_tc_map(ndev, tc_nums - 1);
133 +       prio_next = netdev_get_prio_tc_map(ndev, tc_nums - 2);
134 +
135 +       /* Support highest prio and second prio tc in cbs mode */
136 +       if (tc != prio_top && tc != prio_next)
137 +               return -EOPNOTSUPP;
138 +
139 +       if (!cbs->enable) {
140 +               /* Make sure the other TC that are numerically
141 +                * lower than this TC have been disabled.
142 +                */
143 +               if (tc == prio_top &&
144 +                   enetc_get_cbs_enable(&si->hw, prio_next)) {
145 +                       dev_err(&ndev->dev,
146 +                               "Disable TC%d before disable TC%d\n",
147 +                               prio_next, tc);
148 +                       return -EINVAL;
149 +               }
150 +
151 +               enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0);
152 +               enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0);
153 +
154 +               return 0;
155 +       }
156 +
157 +       if (cbs->idleslope - cbs->sendslope != port_transmit_rate * 1000L ||
158 +           cbs->idleslope < 0 || cbs->sendslope > 0)
159 +               return -EOPNOTSUPP;
160 +
161 +       port_frame_max_size = ndev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
162 +
163 +       bw = cbs->idleslope / (port_transmit_rate * 10UL);
164 +
165 +       /* Make sure the other TC that are numerically
166 +        * higher than this TC have been enabled.
167 +        */
168 +       if (tc == prio_next) {
169 +               if (!enetc_get_cbs_enable(&si->hw, prio_top)) {
170 +                       dev_err(&ndev->dev,
171 +                               "Enable TC%d first before enable TC%d\n",
172 +                               prio_top, prio_next);
173 +                       return -EINVAL;
174 +               }
175 +               bw_sum += enetc_get_cbs_bw(&si->hw, prio_top);
176 +       }
177 +
178 +       if (bw_sum + bw >= 100) {
179 +               dev_err(&ndev->dev,
180 +                       "The sum of all CBS Bandwidth can't exceed 100\n");
181 +               return -EINVAL;
182 +       }
183 +
184 +       tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc));
185 +
186 +       /* For top prio TC, the max_interfrence_size is maxSizedFrame.
187 +        *
188 +        * For next prio TC, the max_interfrence_size is calculated as below:
189 +        *
190 +        *      max_interference_size = M0 + Ma + Ra * M0 / (R0 - Ra)
191 +        *
192 +        *      - RA: idleSlope for AVB Class A
193 +        *      - R0: port transmit rate
194 +        *      - M0: maximum sized frame for the port
195 +        *      - MA: maximum sized frame for AVB Class A
196 +        */
197 +
198 +       if (tc == prio_top) {
199 +               max_interference_size = port_frame_max_size * 8;
200 +       } else {
201 +               u32 m0, ma, r0, ra;
202 +
203 +               m0 = port_frame_max_size * 8;
204 +               ma = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(prio_top)) * 8;
205 +               ra = enetc_get_cbs_bw(&si->hw, prio_top) *
206 +                       port_transmit_rate * 10000ULL;
207 +               r0 = port_transmit_rate * 1000000ULL;
208 +               max_interference_size = m0 + ma +
209 +                       (u32)div_u64((u64)ra * m0, r0 - ra);
210 +       }
211 +
212 +       /* hiCredit bits calculate by:
213 +        *
214 +        * maxSizedFrame * (idleSlope/portTxRate)
215 +        */
216 +       hi_credit_bit = max_interference_size * bw / 100;
217 +
218 +       /* hiCredit bits to hiCredit register need to calculated as:
219 +        *
220 +        * (enetClockFrequency / portTransmitRate) * 100
221 +        */
222 +       hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit,
223 +                                    port_transmit_rate * 1000000ULL);
224 +
225 +       enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit_reg);
226 +
227 +       /* Set bw register and enable this traffic class */
228 +       enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE);
229 +
230 +       return 0;
231 +}