]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/net/dsa/sja1105/sja1105_tas.c
slip: Fix use-after-free Read in slip_open
[mirror_ubuntu-jammy-kernel.git] / drivers / net / dsa / sja1105 / sja1105_tas.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
3 */
4 #include "sja1105.h"
5
6 #define SJA1105_TAS_CLKSRC_DISABLED 0
7 #define SJA1105_TAS_CLKSRC_STANDALONE 1
8 #define SJA1105_TAS_CLKSRC_AS6802 2
9 #define SJA1105_TAS_CLKSRC_PTP 3
10 #define SJA1105_TAS_MAX_DELTA BIT(19)
11 #define SJA1105_GATE_MASK GENMASK_ULL(SJA1105_NUM_TC - 1, 0)
12
13 /* This is not a preprocessor macro because the "ns" argument may or may not be
14 * s64 at caller side. This ensures it is properly type-cast before div_s64.
15 */
16 static s64 ns_to_sja1105_delta(s64 ns)
17 {
18 return div_s64(ns, 200);
19 }
20
21 /* Lo and behold: the egress scheduler from hell.
22 *
23 * At the hardware level, the Time-Aware Shaper holds a global linear arrray of
24 * all schedule entries for all ports. These are the Gate Control List (GCL)
25 * entries, let's call them "timeslots" for short. This linear array of
26 * timeslots is held in BLK_IDX_SCHEDULE.
27 *
28 * Then there are a maximum of 8 "execution threads" inside the switch, which
29 * iterate cyclically through the "schedule". Each "cycle" has an entry point
30 * and an exit point, both being timeslot indices in the schedule table. The
31 * hardware calls each cycle a "subschedule".
32 *
33 * Subschedule (cycle) i starts when
34 * ptpclkval >= ptpschtm + BLK_IDX_SCHEDULE_ENTRY_POINTS[i].delta.
35 *
36 * The hardware scheduler iterates BLK_IDX_SCHEDULE with a k ranging from
37 * k = BLK_IDX_SCHEDULE_ENTRY_POINTS[i].address to
38 * k = BLK_IDX_SCHEDULE_PARAMS.subscheind[i]
39 *
40 * For each schedule entry (timeslot) k, the engine executes the gate control
41 * list entry for the duration of BLK_IDX_SCHEDULE[k].delta.
42 *
43 * +---------+
44 * | | BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS
45 * +---------+
46 * |
47 * +-----------------+
48 * | .actsubsch
49 * BLK_IDX_SCHEDULE_ENTRY_POINTS v
50 * +-------+-------+
51 * |cycle 0|cycle 1|
52 * +-------+-------+
53 * | | | |
54 * +----------------+ | | +-------------------------------------+
55 * | .subschindx | | .subschindx |
56 * | | +---------------+ |
57 * | .address | .address | |
58 * | | | |
59 * | | | |
60 * | BLK_IDX_SCHEDULE v v |
61 * | +-------+-------+-------+-------+-------+------+ |
62 * | |entry 0|entry 1|entry 2|entry 3|entry 4|entry5| |
63 * | +-------+-------+-------+-------+-------+------+ |
64 * | ^ ^ ^ ^ |
65 * | | | | | |
66 * | +-------------------------+ | | | |
67 * | | +-------------------------------+ | | |
68 * | | | +-------------------+ | |
69 * | | | | | |
70 * | +---------------------------------------------------------------+ |
71 * | |subscheind[0]<=subscheind[1]<=subscheind[2]<=...<=subscheind[7]| |
72 * | +---------------------------------------------------------------+ |
73 * | ^ ^ BLK_IDX_SCHEDULE_PARAMS |
74 * | | | |
75 * +--------+ +-------------------------------------------+
76 *
77 * In the above picture there are two subschedules (cycles):
78 *
79 * - cycle 0: iterates the schedule table from 0 to 2 (and back)
80 * - cycle 1: iterates the schedule table from 3 to 5 (and back)
81 *
82 * All other possible execution threads must be marked as unused by making
83 * their "subschedule end index" (subscheind) equal to the last valid
84 * subschedule's end index (in this case 5).
85 */
86 static int sja1105_init_scheduling(struct sja1105_private *priv)
87 {
88 struct sja1105_schedule_entry_points_entry *schedule_entry_points;
89 struct sja1105_schedule_entry_points_params_entry
90 *schedule_entry_points_params;
91 struct sja1105_schedule_params_entry *schedule_params;
92 struct sja1105_tas_data *tas_data = &priv->tas_data;
93 struct sja1105_schedule_entry *schedule;
94 struct sja1105_table *table;
95 int schedule_start_idx;
96 s64 entry_point_delta;
97 int schedule_end_idx;
98 int num_entries = 0;
99 int num_cycles = 0;
100 int cycle = 0;
101 int i, k = 0;
102 int port;
103
104 /* Discard previous Schedule Table */
105 table = &priv->static_config.tables[BLK_IDX_SCHEDULE];
106 if (table->entry_count) {
107 kfree(table->entries);
108 table->entry_count = 0;
109 }
110
111 /* Discard previous Schedule Entry Points Parameters Table */
112 table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS];
113 if (table->entry_count) {
114 kfree(table->entries);
115 table->entry_count = 0;
116 }
117
118 /* Discard previous Schedule Parameters Table */
119 table = &priv->static_config.tables[BLK_IDX_SCHEDULE_PARAMS];
120 if (table->entry_count) {
121 kfree(table->entries);
122 table->entry_count = 0;
123 }
124
125 /* Discard previous Schedule Entry Points Table */
126 table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS];
127 if (table->entry_count) {
128 kfree(table->entries);
129 table->entry_count = 0;
130 }
131
132 /* Figure out the dimensioning of the problem */
133 for (port = 0; port < SJA1105_NUM_PORTS; port++) {
134 if (tas_data->offload[port]) {
135 num_entries += tas_data->offload[port]->num_entries;
136 num_cycles++;
137 }
138 }
139
140 /* Nothing to do */
141 if (!num_cycles)
142 return 0;
143
144 /* Pre-allocate space in the static config tables */
145
146 /* Schedule Table */
147 table = &priv->static_config.tables[BLK_IDX_SCHEDULE];
148 table->entries = kcalloc(num_entries, table->ops->unpacked_entry_size,
149 GFP_KERNEL);
150 if (!table->entries)
151 return -ENOMEM;
152 table->entry_count = num_entries;
153 schedule = table->entries;
154
155 /* Schedule Points Parameters Table */
156 table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS];
157 table->entries = kcalloc(SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT,
158 table->ops->unpacked_entry_size, GFP_KERNEL);
159 if (!table->entries)
160 /* Previously allocated memory will be freed automatically in
161 * sja1105_static_config_free. This is true for all early
162 * returns below.
163 */
164 return -ENOMEM;
165 table->entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT;
166 schedule_entry_points_params = table->entries;
167
168 /* Schedule Parameters Table */
169 table = &priv->static_config.tables[BLK_IDX_SCHEDULE_PARAMS];
170 table->entries = kcalloc(SJA1105_MAX_SCHEDULE_PARAMS_COUNT,
171 table->ops->unpacked_entry_size, GFP_KERNEL);
172 if (!table->entries)
173 return -ENOMEM;
174 table->entry_count = SJA1105_MAX_SCHEDULE_PARAMS_COUNT;
175 schedule_params = table->entries;
176
177 /* Schedule Entry Points Table */
178 table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS];
179 table->entries = kcalloc(num_cycles, table->ops->unpacked_entry_size,
180 GFP_KERNEL);
181 if (!table->entries)
182 return -ENOMEM;
183 table->entry_count = num_cycles;
184 schedule_entry_points = table->entries;
185
186 /* Finally start populating the static config tables */
187 schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_STANDALONE;
188 schedule_entry_points_params->actsubsch = num_cycles - 1;
189
190 for (port = 0; port < SJA1105_NUM_PORTS; port++) {
191 const struct tc_taprio_qopt_offload *offload;
192
193 offload = tas_data->offload[port];
194 if (!offload)
195 continue;
196
197 schedule_start_idx = k;
198 schedule_end_idx = k + offload->num_entries - 1;
199 /* TODO this is the base time for the port's subschedule,
200 * relative to PTPSCHTM. But as we're using the standalone
201 * clock source and not PTP clock as time reference, there's
202 * little point in even trying to put more logic into this,
203 * like preserving the phases between the subschedules of
204 * different ports. We'll get all of that when switching to the
205 * PTP clock source.
206 */
207 entry_point_delta = 1;
208
209 schedule_entry_points[cycle].subschindx = cycle;
210 schedule_entry_points[cycle].delta = entry_point_delta;
211 schedule_entry_points[cycle].address = schedule_start_idx;
212
213 /* The subschedule end indices need to be
214 * monotonically increasing.
215 */
216 for (i = cycle; i < 8; i++)
217 schedule_params->subscheind[i] = schedule_end_idx;
218
219 for (i = 0; i < offload->num_entries; i++, k++) {
220 s64 delta_ns = offload->entries[i].interval;
221
222 schedule[k].delta = ns_to_sja1105_delta(delta_ns);
223 schedule[k].destports = BIT(port);
224 schedule[k].resmedia_en = true;
225 schedule[k].resmedia = SJA1105_GATE_MASK &
226 ~offload->entries[i].gate_mask;
227 }
228 cycle++;
229 }
230
231 return 0;
232 }
233
234 /* Be there 2 port subschedules, each executing an arbitrary number of gate
235 * open/close events cyclically.
236 * None of those gate events must ever occur at the exact same time, otherwise
237 * the switch is known to act in exotically strange ways.
238 * However the hardware doesn't bother performing these integrity checks.
239 * So here we are with the task of validating whether the new @admin offload
240 * has any conflict with the already established TAS configuration in
241 * tas_data->offload. We already know the other ports are in harmony with one
242 * another, otherwise we wouldn't have saved them.
243 * Each gate event executes periodically, with a period of @cycle_time and a
244 * phase given by its cycle's @base_time plus its offset within the cycle
245 * (which in turn is given by the length of the events prior to it).
246 * There are two aspects to possible collisions:
247 * - Collisions within one cycle's (actually the longest cycle's) time frame.
248 * For that, we need to compare the cartesian product of each possible
249 * occurrence of each event within one cycle time.
250 * - Collisions in the future. Events may not collide within one cycle time,
251 * but if two port schedules don't have the same periodicity (aka the cycle
252 * times aren't multiples of one another), they surely will some time in the
253 * future (actually they will collide an infinite amount of times).
254 */
255 static bool
256 sja1105_tas_check_conflicts(struct sja1105_private *priv, int port,
257 const struct tc_taprio_qopt_offload *admin)
258 {
259 struct sja1105_tas_data *tas_data = &priv->tas_data;
260 const struct tc_taprio_qopt_offload *offload;
261 s64 max_cycle_time, min_cycle_time;
262 s64 delta1, delta2;
263 s64 rbt1, rbt2;
264 s64 stop_time;
265 s64 t1, t2;
266 int i, j;
267 s32 rem;
268
269 offload = tas_data->offload[port];
270 if (!offload)
271 return false;
272
273 /* Check if the two cycle times are multiples of one another.
274 * If they aren't, then they will surely collide.
275 */
276 max_cycle_time = max(offload->cycle_time, admin->cycle_time);
277 min_cycle_time = min(offload->cycle_time, admin->cycle_time);
278 div_s64_rem(max_cycle_time, min_cycle_time, &rem);
279 if (rem)
280 return true;
281
282 /* Calculate the "reduced" base time of each of the two cycles
283 * (transposed back as close to 0 as possible) by dividing to
284 * the cycle time.
285 */
286 div_s64_rem(offload->base_time, offload->cycle_time, &rem);
287 rbt1 = rem;
288
289 div_s64_rem(admin->base_time, admin->cycle_time, &rem);
290 rbt2 = rem;
291
292 stop_time = max_cycle_time + max(rbt1, rbt2);
293
294 /* delta1 is the relative base time of each GCL entry within
295 * the established ports' TAS config.
296 */
297 for (i = 0, delta1 = 0;
298 i < offload->num_entries;
299 delta1 += offload->entries[i].interval, i++) {
300 /* delta2 is the relative base time of each GCL entry
301 * within the newly added TAS config.
302 */
303 for (j = 0, delta2 = 0;
304 j < admin->num_entries;
305 delta2 += admin->entries[j].interval, j++) {
306 /* t1 follows all possible occurrences of the
307 * established ports' GCL entry i within the
308 * first cycle time.
309 */
310 for (t1 = rbt1 + delta1;
311 t1 <= stop_time;
312 t1 += offload->cycle_time) {
313 /* t2 follows all possible occurrences
314 * of the newly added GCL entry j
315 * within the first cycle time.
316 */
317 for (t2 = rbt2 + delta2;
318 t2 <= stop_time;
319 t2 += admin->cycle_time) {
320 if (t1 == t2) {
321 dev_warn(priv->ds->dev,
322 "GCL entry %d collides with entry %d of port %d\n",
323 j, i, port);
324 return true;
325 }
326 }
327 }
328 }
329 }
330
331 return false;
332 }
333
334 int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port,
335 struct tc_taprio_qopt_offload *admin)
336 {
337 struct sja1105_private *priv = ds->priv;
338 struct sja1105_tas_data *tas_data = &priv->tas_data;
339 int other_port, rc, i;
340
341 /* Can't change an already configured port (must delete qdisc first).
342 * Can't delete the qdisc from an unconfigured port.
343 */
344 if (!!tas_data->offload[port] == admin->enable)
345 return -EINVAL;
346
347 if (!admin->enable) {
348 taprio_offload_free(tas_data->offload[port]);
349 tas_data->offload[port] = NULL;
350
351 rc = sja1105_init_scheduling(priv);
352 if (rc < 0)
353 return rc;
354
355 return sja1105_static_config_reload(priv);
356 }
357
358 /* The cycle time extension is the amount of time the last cycle from
359 * the old OPER needs to be extended in order to phase-align with the
360 * base time of the ADMIN when that becomes the new OPER.
361 * But of course our switch needs to be reset to switch-over between
362 * the ADMIN and the OPER configs - so much for a seamless transition.
363 * So don't add insult over injury and just say we don't support cycle
364 * time extension.
365 */
366 if (admin->cycle_time_extension)
367 return -ENOTSUPP;
368
369 if (!ns_to_sja1105_delta(admin->base_time)) {
370 dev_err(ds->dev, "A base time of zero is not hardware-allowed\n");
371 return -ERANGE;
372 }
373
374 for (i = 0; i < admin->num_entries; i++) {
375 s64 delta_ns = admin->entries[i].interval;
376 s64 delta_cycles = ns_to_sja1105_delta(delta_ns);
377 bool too_long, too_short;
378
379 too_long = (delta_cycles >= SJA1105_TAS_MAX_DELTA);
380 too_short = (delta_cycles == 0);
381 if (too_long || too_short) {
382 dev_err(priv->ds->dev,
383 "Interval %llu too %s for GCL entry %d\n",
384 delta_ns, too_long ? "long" : "short", i);
385 return -ERANGE;
386 }
387 }
388
389 for (other_port = 0; other_port < SJA1105_NUM_PORTS; other_port++) {
390 if (other_port == port)
391 continue;
392
393 if (sja1105_tas_check_conflicts(priv, other_port, admin))
394 return -ERANGE;
395 }
396
397 tas_data->offload[port] = taprio_offload_get(admin);
398
399 rc = sja1105_init_scheduling(priv);
400 if (rc < 0)
401 return rc;
402
403 return sja1105_static_config_reload(priv);
404 }
405
406 void sja1105_tas_setup(struct dsa_switch *ds)
407 {
408 }
409
410 void sja1105_tas_teardown(struct dsa_switch *ds)
411 {
412 struct sja1105_private *priv = ds->priv;
413 struct tc_taprio_qopt_offload *offload;
414 int port;
415
416 for (port = 0; port < SJA1105_NUM_PORTS; port++) {
417 offload = priv->tas_data.offload[port];
418 if (!offload)
419 continue;
420
421 taprio_offload_free(offload);
422 }
423 }