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