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->qbv_enable)
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 txqctl |= IGC_TXQCTL_STRICT_CYCLE |
114 IGC_TXQCTL_STRICT_END;
115
116 if (ring->launchtime_enable)
117 txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
118
119 /* Skip configuring CBS for Q2 and Q3 */
120 if (i > 1)
121 goto skip_cbs;
122
123 if (ring->cbs_enable) {
124 if (i == 0)
125 txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
126 else
127 txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
128
129 /* According to i225 datasheet section 7.5.2.7, we
130 * should set the 'idleSlope' field from TQAVCC
131 * register following the equation:
132 *
133 * value = link-speed 0x7736 * BW * 0.2
134 * ---------- * ----------------- (E1)
135 * 100Mbps 2.5
136 *
137 * Note that 'link-speed' is in Mbps.
138 *
139 * 'BW' is the percentage bandwidth out of full
140 * link speed which can be found with the
141 * following equation. Note that idleSlope here
142 * is the parameter from this function
143 * which is in kbps.
144 *
145 * BW = idleSlope
146 * ----------------- (E2)
147 * link-speed * 1000
148 *
149 * That said, we can come up with a generic
150 * equation to calculate the value we should set
151 * it TQAVCC register by replacing 'BW' in E1 by E2.
152 * The resulting equation is:
153 *
154 * value = link-speed * 0x7736 * idleSlope * 0.2
155 * ------------------------------------- (E3)
156 * 100 * 2.5 * link-speed * 1000
157 *
158 * 'link-speed' is present in both sides of the
159 * fraction so it is canceled out. The final
160 * equation is the following:
161 *
162 * value = idleSlope * 61036
163 * ----------------- (E4)
164 * 2500000
165 *
166 * NOTE: For i225, given the above, we can see
167 * that idleslope is represented in
168 * 40.959433 kbps units by the value at
169 * the TQAVCC register (2.5Gbps / 61036),
170 * which reduces the granularity for
171 * idleslope increments.
172 *
173 * In i225 controller, the sendSlope and loCredit
174 * parameters from CBS are not configurable
175 * by software so we don't do any
176 * 'controller configuration' in respect to
177 * these parameters.
178 */
179 cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
180 * 61036ULL, 2500000);
181
182 tqavcc = rd32(IGC_TQAVCC(i));
183 tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
184 tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
185 wr32(IGC_TQAVCC(i), tqavcc);
186
187 wr32(IGC_TQAVHC(i),
188 0x80000000 + ring->hicredit * 0x7735);
189 } else {
190 /* Disable any CBS for the queue */
191 txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
192
193 /* Set idleSlope to zero. */
194 tqavcc = rd32(IGC_TQAVCC(i));
195 tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
196 IGC_TQAVCC_KEEP_CREDITS);
197 wr32(IGC_TQAVCC(i), tqavcc);
198
199 /* Set hiCredit to zero. */
200 wr32(IGC_TQAVHC(i), 0);
201 }
202 skip_cbs:
203 wr32(IGC_TXQCTL(i), txqctl);
204 }
205
206 nsec = rd32(IGC_SYSTIML);
207 sec = rd32(IGC_SYSTIMH);
208
209 systim = ktime_set(sec, nsec);
210
211 if (ktime_compare(systim, base_time) > 0) {
212 s64 n;
213
214 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
215 base_time = ktime_add_ns(base_time, (n + 1) * cycle);
216 }
217
218 baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
219
220 wr32(IGC_BASET_H, baset_h);
221 wr32(IGC_BASET_L, baset_l);
222
223 return 0;
224 }
225
igc_tsn_reset(struct igc_adapter * adapter)226 int igc_tsn_reset(struct igc_adapter *adapter)
227 {
228 unsigned int new_flags;
229 int err = 0;
230
231 new_flags = igc_tsn_new_flags(adapter);
232
233 if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
234 return igc_tsn_disable_offload(adapter);
235
236 err = igc_tsn_enable_offload(adapter);
237 if (err < 0)
238 return err;
239
240 adapter->flags = new_flags;
241
242 return err;
243 }
244
igc_tsn_offload_apply(struct igc_adapter * adapter)245 int igc_tsn_offload_apply(struct igc_adapter *adapter)
246 {
247 int err;
248
249 if (netif_running(adapter->netdev)) {
250 schedule_work(&adapter->reset_task);
251 return 0;
252 }
253
254 err = igc_tsn_enable_offload(adapter);
255 if (err < 0)
256 return err;
257
258 adapter->flags = igc_tsn_new_flags(adapter);
259 return 0;
260 }
261