1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Intel Corporation */
3
4 #include "igc.h"
5 #include "igc_tsn.h"
6
is_any_launchtime(struct igc_adapter * adapter)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
is_cbs_enabled(struct igc_adapter * adapter)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
igc_tsn_new_flags(struct igc_adapter * adapter)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 */
igc_tsn_disable_offload(struct igc_adapter * adapter)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
igc_tsn_enable_offload(struct igc_adapter * adapter)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
igc_tsn_reset(struct igc_adapter * adapter)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
igc_tsn_offload_apply(struct igc_adapter * adapter)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 }
268