1
2
3
4#include "igc.h"
5#include "igc_tsn.h"
6
7static 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
21static 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
35static 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
52
53
54static 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
82static 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
115
116
117
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
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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
198 txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
199
200
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
207 wr32(IGC_TQAVHC(i), 0);
208 }
209skip_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
233int 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
252int 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