]> Git Repo - linux.git/blob - drivers/net/ethernet/intel/igc/igc_tsn.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux.git] / drivers / net / ethernet / intel / igc / igc_tsn.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c)  2019 Intel Corporation */
3
4 #include "igc.h"
5 #include "igc_tsn.h"
6
7 static bool is_any_launchtime(struct igc_adapter *adapter)
8 {
9         int i;
10
11         for (i = 0; i < adapter->num_tx_queues; i++) {
12                 struct igc_ring *ring = adapter->tx_ring[i];
13
14                 if (ring->launchtime_enable)
15                         return true;
16         }
17
18         return false;
19 }
20
21 static bool is_cbs_enabled(struct igc_adapter *adapter)
22 {
23         int i;
24
25         for (i = 0; i < adapter->num_tx_queues; i++) {
26                 struct igc_ring *ring = adapter->tx_ring[i];
27
28                 if (ring->cbs_enable)
29                         return true;
30         }
31
32         return false;
33 }
34
35 static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
36 {
37         unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
38
39         if (adapter->base_time)
40                 new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
41
42         if (is_any_launchtime(adapter))
43                 new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
44
45         if (is_cbs_enabled(adapter))
46                 new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
47
48         return new_flags;
49 }
50
51 /* Returns the TSN specific registers to their default values after
52  * the adapter is reset.
53  */
54 static int igc_tsn_disable_offload(struct igc_adapter *adapter)
55 {
56         struct igc_hw *hw = &adapter->hw;
57         u32 tqavctrl;
58         int i;
59
60         wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
61         wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
62
63         tqavctrl = rd32(IGC_TQAVCTRL);
64         tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
65                       IGC_TQAVCTRL_ENHANCED_QAV);
66         wr32(IGC_TQAVCTRL, tqavctrl);
67
68         for (i = 0; i < adapter->num_tx_queues; i++) {
69                 wr32(IGC_TXQCTL(i), 0);
70                 wr32(IGC_STQT(i), 0);
71                 wr32(IGC_ENDQT(i), NSEC_PER_SEC);
72         }
73
74         wr32(IGC_QBVCYCLET_S, 0);
75         wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
76
77         adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
78
79         return 0;
80 }
81
82 static int igc_tsn_enable_offload(struct igc_adapter *adapter)
83 {
84         struct igc_hw *hw = &adapter->hw;
85         u32 tqavctrl, baset_l, baset_h;
86         u32 sec, nsec, cycle;
87         ktime_t base_time, systim;
88         int i;
89
90         cycle = adapter->cycle_time;
91         base_time = adapter->base_time;
92
93         wr32(IGC_TSAUXC, 0);
94         wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
95         wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
96
97         tqavctrl = rd32(IGC_TQAVCTRL);
98         tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
99         wr32(IGC_TQAVCTRL, tqavctrl);
100
101         wr32(IGC_QBVCYCLET_S, cycle);
102         wr32(IGC_QBVCYCLET, cycle);
103
104         for (i = 0; i < adapter->num_tx_queues; i++) {
105                 struct igc_ring *ring = adapter->tx_ring[i];
106                 u32 txqctl = 0;
107                 u16 cbs_value;
108                 u32 tqavcc;
109
110                 wr32(IGC_STQT(i), ring->start_time);
111                 wr32(IGC_ENDQT(i), ring->end_time);
112
113                 if (adapter->base_time) {
114                         /* If we have a base_time we are in "taprio"
115                          * mode and we need to be strict about the
116                          * cycles: only transmit a packet if it can be
117                          * completed during that cycle.
118                          */
119                         txqctl |= IGC_TXQCTL_STRICT_CYCLE |
120                                 IGC_TXQCTL_STRICT_END;
121                 }
122
123                 if (ring->launchtime_enable)
124                         txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
125
126                 /* Skip configuring CBS for Q2 and Q3 */
127                 if (i > 1)
128                         goto skip_cbs;
129
130                 if (ring->cbs_enable) {
131                         if (i == 0)
132                                 txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
133                         else
134                                 txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
135
136                         /* According to i225 datasheet section 7.5.2.7, we
137                          * should set the 'idleSlope' field from TQAVCC
138                          * register following the equation:
139                          *
140                          * value = link-speed   0x7736 * BW * 0.2
141                          *         ---------- *  -----------------         (E1)
142                          *          100Mbps            2.5
143                          *
144                          * Note that 'link-speed' is in Mbps.
145                          *
146                          * 'BW' is the percentage bandwidth out of full
147                          * link speed which can be found with the
148                          * following equation. Note that idleSlope here
149                          * is the parameter from this function
150                          * which is in kbps.
151                          *
152                          *     BW =     idleSlope
153                          *          -----------------                      (E2)
154                          *          link-speed * 1000
155                          *
156                          * That said, we can come up with a generic
157                          * equation to calculate the value we should set
158                          * it TQAVCC register by replacing 'BW' in E1 by E2.
159                          * The resulting equation is:
160                          *
161                          * value = link-speed * 0x7736 * idleSlope * 0.2
162                          *         -------------------------------------   (E3)
163                          *             100 * 2.5 * link-speed * 1000
164                          *
165                          * 'link-speed' is present in both sides of the
166                          * fraction so it is canceled out. The final
167                          * equation is the following:
168                          *
169                          *     value = idleSlope * 61036
170                          *             -----------------                   (E4)
171                          *                  2500000
172                          *
173                          * NOTE: For i225, given the above, we can see
174                          *       that idleslope is represented in
175                          *       40.959433 kbps units by the value at
176                          *       the TQAVCC register (2.5Gbps / 61036),
177                          *       which reduces the granularity for
178                          *       idleslope increments.
179                          *
180                          * In i225 controller, the sendSlope and loCredit
181                          * parameters from CBS are not configurable
182                          * by software so we don't do any
183                          * 'controller configuration' in respect to
184                          * these parameters.
185                          */
186                         cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
187                                                      * 61036ULL, 2500000);
188
189                         tqavcc = rd32(IGC_TQAVCC(i));
190                         tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
191                         tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
192                         wr32(IGC_TQAVCC(i), tqavcc);
193
194                         wr32(IGC_TQAVHC(i),
195                              0x80000000 + ring->hicredit * 0x7735);
196                 } else {
197                         /* Disable any CBS for the queue */
198                         txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
199
200                         /* Set idleSlope to zero. */
201                         tqavcc = rd32(IGC_TQAVCC(i));
202                         tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
203                                     IGC_TQAVCC_KEEP_CREDITS);
204                         wr32(IGC_TQAVCC(i), tqavcc);
205
206                         /* Set hiCredit to zero. */
207                         wr32(IGC_TQAVHC(i), 0);
208                 }
209 skip_cbs:
210                 wr32(IGC_TXQCTL(i), txqctl);
211         }
212
213         nsec = rd32(IGC_SYSTIML);
214         sec = rd32(IGC_SYSTIMH);
215
216         systim = ktime_set(sec, nsec);
217
218         if (ktime_compare(systim, base_time) > 0) {
219                 s64 n;
220
221                 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
222                 base_time = ktime_add_ns(base_time, (n + 1) * cycle);
223         }
224
225         baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
226
227         wr32(IGC_BASET_H, baset_h);
228         wr32(IGC_BASET_L, baset_l);
229
230         return 0;
231 }
232
233 int igc_tsn_reset(struct igc_adapter *adapter)
234 {
235         unsigned int new_flags;
236         int err = 0;
237
238         new_flags = igc_tsn_new_flags(adapter);
239
240         if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
241                 return igc_tsn_disable_offload(adapter);
242
243         err = igc_tsn_enable_offload(adapter);
244         if (err < 0)
245                 return err;
246
247         adapter->flags = new_flags;
248
249         return err;
250 }
251
252 int igc_tsn_offload_apply(struct igc_adapter *adapter)
253 {
254         int err;
255
256         if (netif_running(adapter->netdev)) {
257                 schedule_work(&adapter->reset_task);
258                 return 0;
259         }
260
261         err = igc_tsn_enable_offload(adapter);
262         if (err < 0)
263                 return err;
264
265         adapter->flags = igc_tsn_new_flags(adapter);
266         return 0;
267 }
This page took 0.048343 seconds and 4 git commands to generate.