1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (C) 2021 Gerhard Engleder <gerhard@engleder-embedded.com> */ |
3 | |
4 | #include "tsnep.h" |
5 | |
6 | #include <net/pkt_sched.h> |
7 | |
8 | enum tsnep_test { |
9 | TSNEP_TEST_ENABLE = 0, |
10 | TSNEP_TEST_TAPRIO, |
11 | TSNEP_TEST_TAPRIO_CHANGE, |
12 | TSNEP_TEST_TAPRIO_EXTENSION, |
13 | }; |
14 | |
15 | static const char tsnep_test_strings[][ETH_GSTRING_LEN] = { |
16 | "Enable timeout (offline)" , |
17 | "TAPRIO (offline)" , |
18 | "TAPRIO change (offline)" , |
19 | "TAPRIO extension (offline)" , |
20 | }; |
21 | |
22 | #define TSNEP_TEST_COUNT (sizeof(tsnep_test_strings) / ETH_GSTRING_LEN) |
23 | |
24 | static bool enable_gc_timeout(struct tsnep_adapter *adapter) |
25 | { |
26 | iowrite8(TSNEP_GC_ENABLE_TIMEOUT, adapter->addr + TSNEP_GC); |
27 | if (!(ioread32(adapter->addr + TSNEP_GC) & TSNEP_GC_TIMEOUT_ACTIVE)) |
28 | return false; |
29 | |
30 | return true; |
31 | } |
32 | |
33 | static bool gc_timeout_signaled(struct tsnep_adapter *adapter) |
34 | { |
35 | if (ioread32(adapter->addr + TSNEP_GC) & TSNEP_GC_TIMEOUT_SIGNAL) |
36 | return true; |
37 | |
38 | return false; |
39 | } |
40 | |
41 | static bool ack_gc_timeout(struct tsnep_adapter *adapter) |
42 | { |
43 | iowrite8(TSNEP_GC_ENABLE_TIMEOUT, adapter->addr + TSNEP_GC); |
44 | if (ioread32(adapter->addr + TSNEP_GC) & |
45 | (TSNEP_GC_TIMEOUT_ACTIVE | TSNEP_GC_TIMEOUT_SIGNAL)) |
46 | return false; |
47 | return true; |
48 | } |
49 | |
50 | static bool enable_gc(struct tsnep_adapter *adapter, bool a) |
51 | { |
52 | u8 enable; |
53 | u8 active; |
54 | |
55 | if (a) { |
56 | enable = TSNEP_GC_ENABLE_A; |
57 | active = TSNEP_GC_ACTIVE_A; |
58 | } else { |
59 | enable = TSNEP_GC_ENABLE_B; |
60 | active = TSNEP_GC_ACTIVE_B; |
61 | } |
62 | |
63 | iowrite8(enable, adapter->addr + TSNEP_GC); |
64 | if (!(ioread32(adapter->addr + TSNEP_GC) & active)) |
65 | return false; |
66 | |
67 | return true; |
68 | } |
69 | |
70 | static bool disable_gc(struct tsnep_adapter *adapter) |
71 | { |
72 | iowrite8(TSNEP_GC_DISABLE, adapter->addr + TSNEP_GC); |
73 | if (ioread32(adapter->addr + TSNEP_GC) & |
74 | (TSNEP_GC_ACTIVE_A | TSNEP_GC_ACTIVE_B)) |
75 | return false; |
76 | |
77 | return true; |
78 | } |
79 | |
80 | static bool gc_delayed_enable(struct tsnep_adapter *adapter, bool a, int delay) |
81 | { |
82 | u64 before, after; |
83 | u32 time; |
84 | bool enabled; |
85 | |
86 | if (!disable_gc(adapter)) |
87 | return false; |
88 | |
89 | before = ktime_get_ns(); |
90 | |
91 | if (!enable_gc_timeout(adapter)) |
92 | return false; |
93 | |
94 | /* for start time after timeout, the timeout can guarantee, that enable |
95 | * is blocked if too late |
96 | */ |
97 | time = ioread32(adapter->addr + ECM_SYSTEM_TIME_LOW); |
98 | time += TSNEP_GC_TIMEOUT; |
99 | iowrite32(time, adapter->addr + TSNEP_GC_TIME); |
100 | |
101 | ndelay(delay); |
102 | |
103 | enabled = enable_gc(adapter, a); |
104 | after = ktime_get_ns(); |
105 | |
106 | if (delay > TSNEP_GC_TIMEOUT) { |
107 | /* timeout must have blocked enable */ |
108 | if (enabled) |
109 | return false; |
110 | } else if ((after - before) < TSNEP_GC_TIMEOUT * 14 / 16) { |
111 | /* timeout must not have blocked enable */ |
112 | if (!enabled) |
113 | return false; |
114 | } |
115 | |
116 | if (enabled) { |
117 | if (gc_timeout_signaled(adapter)) |
118 | return false; |
119 | } else { |
120 | if (!gc_timeout_signaled(adapter)) |
121 | return false; |
122 | if (!ack_gc_timeout(adapter)) |
123 | return false; |
124 | } |
125 | |
126 | if (!disable_gc(adapter)) |
127 | return false; |
128 | |
129 | return true; |
130 | } |
131 | |
132 | static bool tsnep_test_gc_enable(struct tsnep_adapter *adapter) |
133 | { |
134 | int i; |
135 | |
136 | iowrite32(0x80000001, adapter->addr + TSNEP_GCL_A + 0); |
137 | iowrite32(100000, adapter->addr + TSNEP_GCL_A + 4); |
138 | |
139 | for (i = 0; i < 200000; i += 100) { |
140 | if (!gc_delayed_enable(adapter, a: true, delay: i)) |
141 | return false; |
142 | } |
143 | |
144 | iowrite32(0x80000001, adapter->addr + TSNEP_GCL_B + 0); |
145 | iowrite32(100000, adapter->addr + TSNEP_GCL_B + 4); |
146 | |
147 | for (i = 0; i < 200000; i += 100) { |
148 | if (!gc_delayed_enable(adapter, a: false, delay: i)) |
149 | return false; |
150 | } |
151 | |
152 | return true; |
153 | } |
154 | |
155 | static void delay_base_time(struct tsnep_adapter *adapter, |
156 | struct tc_taprio_qopt_offload *qopt, s64 ms) |
157 | { |
158 | u64 system_time; |
159 | u64 base_time = ktime_to_ns(kt: qopt->base_time); |
160 | u64 n; |
161 | |
162 | tsnep_get_system_time(adapter, time: &system_time); |
163 | system_time += ms * 1000000; |
164 | n = div64_u64(dividend: system_time - base_time, divisor: qopt->cycle_time); |
165 | |
166 | qopt->base_time = ktime_add_ns(qopt->base_time, |
167 | (n + 1) * qopt->cycle_time); |
168 | } |
169 | |
170 | static void get_gate_state(struct tsnep_adapter *adapter, u32 *gc, u32 *gc_time, |
171 | u64 *system_time) |
172 | { |
173 | u32 time_high_before; |
174 | u32 time_low; |
175 | u32 time_high; |
176 | u32 gc_time_before; |
177 | |
178 | time_high = ioread32(adapter->addr + ECM_SYSTEM_TIME_HIGH); |
179 | *gc_time = ioread32(adapter->addr + TSNEP_GC_TIME); |
180 | do { |
181 | time_low = ioread32(adapter->addr + ECM_SYSTEM_TIME_LOW); |
182 | *gc = ioread32(adapter->addr + TSNEP_GC); |
183 | |
184 | gc_time_before = *gc_time; |
185 | *gc_time = ioread32(adapter->addr + TSNEP_GC_TIME); |
186 | time_high_before = time_high; |
187 | time_high = ioread32(adapter->addr + ECM_SYSTEM_TIME_HIGH); |
188 | } while ((time_high != time_high_before) || |
189 | (*gc_time != gc_time_before)); |
190 | |
191 | *system_time = (((u64)time_high) << 32) | ((u64)time_low); |
192 | } |
193 | |
194 | static int get_operation(struct tsnep_gcl *gcl, u64 system_time, u64 *next) |
195 | { |
196 | u64 n = div64_u64(dividend: system_time - gcl->base_time, divisor: gcl->cycle_time); |
197 | u64 cycle_start = gcl->base_time + gcl->cycle_time * n; |
198 | int i; |
199 | |
200 | *next = cycle_start; |
201 | for (i = 0; i < gcl->count; i++) { |
202 | *next += gcl->operation[i].interval; |
203 | if (*next > system_time) |
204 | break; |
205 | } |
206 | |
207 | return i; |
208 | } |
209 | |
210 | static bool check_gate(struct tsnep_adapter *adapter) |
211 | { |
212 | u32 gc_time; |
213 | u32 gc; |
214 | u64 system_time; |
215 | struct tsnep_gcl *curr; |
216 | struct tsnep_gcl *prev; |
217 | u64 next_time; |
218 | u8 gate_open; |
219 | u8 next_gate_open; |
220 | |
221 | get_gate_state(adapter, gc: &gc, gc_time: &gc_time, system_time: &system_time); |
222 | |
223 | if (gc & TSNEP_GC_ACTIVE_A) { |
224 | curr = &adapter->gcl[0]; |
225 | prev = &adapter->gcl[1]; |
226 | } else if (gc & TSNEP_GC_ACTIVE_B) { |
227 | curr = &adapter->gcl[1]; |
228 | prev = &adapter->gcl[0]; |
229 | } else { |
230 | return false; |
231 | } |
232 | if (curr->start_time <= system_time) { |
233 | /* GCL is already active */ |
234 | int index; |
235 | |
236 | index = get_operation(gcl: curr, system_time, next: &next_time); |
237 | gate_open = curr->operation[index].properties & TSNEP_GCL_MASK; |
238 | if (index == curr->count - 1) |
239 | index = 0; |
240 | else |
241 | index++; |
242 | next_gate_open = |
243 | curr->operation[index].properties & TSNEP_GCL_MASK; |
244 | } else if (curr->change) { |
245 | /* operation of previous GCL is active */ |
246 | int index; |
247 | u64 start_before; |
248 | u64 n; |
249 | |
250 | index = get_operation(gcl: prev, system_time, next: &next_time); |
251 | next_time = curr->start_time; |
252 | start_before = prev->base_time; |
253 | n = div64_u64(dividend: curr->start_time - start_before, |
254 | divisor: prev->cycle_time); |
255 | start_before += n * prev->cycle_time; |
256 | if (curr->start_time == start_before) |
257 | start_before -= prev->cycle_time; |
258 | if (((start_before + prev->cycle_time_extension) >= |
259 | curr->start_time) && |
260 | (curr->start_time - prev->cycle_time_extension <= |
261 | system_time)) { |
262 | /* extend */ |
263 | index = prev->count - 1; |
264 | } |
265 | gate_open = prev->operation[index].properties & TSNEP_GCL_MASK; |
266 | next_gate_open = |
267 | curr->operation[0].properties & TSNEP_GCL_MASK; |
268 | } else { |
269 | /* GCL is waiting for start */ |
270 | next_time = curr->start_time; |
271 | gate_open = 0xFF; |
272 | next_gate_open = curr->operation[0].properties & TSNEP_GCL_MASK; |
273 | } |
274 | |
275 | if (gc_time != (next_time & 0xFFFFFFFF)) { |
276 | dev_err(&adapter->pdev->dev, "gate control time 0x%x!=0x%llx\n" , |
277 | gc_time, next_time); |
278 | return false; |
279 | } |
280 | if (((gc & TSNEP_GC_OPEN) >> TSNEP_GC_OPEN_SHIFT) != gate_open) { |
281 | dev_err(&adapter->pdev->dev, |
282 | "gate control open 0x%02x!=0x%02x\n" , |
283 | ((gc & TSNEP_GC_OPEN) >> TSNEP_GC_OPEN_SHIFT), |
284 | gate_open); |
285 | return false; |
286 | } |
287 | if (((gc & TSNEP_GC_NEXT_OPEN) >> TSNEP_GC_NEXT_OPEN_SHIFT) != |
288 | next_gate_open) { |
289 | dev_err(&adapter->pdev->dev, |
290 | "gate control next open 0x%02x!=0x%02x\n" , |
291 | ((gc & TSNEP_GC_NEXT_OPEN) >> TSNEP_GC_NEXT_OPEN_SHIFT), |
292 | next_gate_open); |
293 | return false; |
294 | } |
295 | |
296 | return true; |
297 | } |
298 | |
299 | static bool check_gate_duration(struct tsnep_adapter *adapter, s64 ms) |
300 | { |
301 | ktime_t start = ktime_get(); |
302 | |
303 | do { |
304 | if (!check_gate(adapter)) |
305 | return false; |
306 | } while (ktime_ms_delta(later: ktime_get(), earlier: start) < ms); |
307 | |
308 | return true; |
309 | } |
310 | |
311 | static bool enable_check_taprio(struct tsnep_adapter *adapter, |
312 | struct tc_taprio_qopt_offload *qopt, s64 ms) |
313 | { |
314 | int retval; |
315 | |
316 | retval = tsnep_tc_setup(netdev: adapter->netdev, type: TC_SETUP_QDISC_TAPRIO, type_data: qopt); |
317 | if (retval) |
318 | return false; |
319 | |
320 | if (!check_gate_duration(adapter, ms)) |
321 | return false; |
322 | |
323 | return true; |
324 | } |
325 | |
326 | static bool disable_taprio(struct tsnep_adapter *adapter) |
327 | { |
328 | struct tc_taprio_qopt_offload qopt; |
329 | int retval; |
330 | |
331 | memset(&qopt, 0, sizeof(qopt)); |
332 | qopt.cmd = TAPRIO_CMD_DESTROY; |
333 | retval = tsnep_tc_setup(netdev: adapter->netdev, type: TC_SETUP_QDISC_TAPRIO, type_data: &qopt); |
334 | if (retval) |
335 | return false; |
336 | |
337 | return true; |
338 | } |
339 | |
340 | static bool run_taprio(struct tsnep_adapter *adapter, |
341 | struct tc_taprio_qopt_offload *qopt, s64 ms) |
342 | { |
343 | if (!enable_check_taprio(adapter, qopt, ms)) |
344 | return false; |
345 | |
346 | if (!disable_taprio(adapter)) |
347 | return false; |
348 | |
349 | return true; |
350 | } |
351 | |
352 | static bool tsnep_test_taprio(struct tsnep_adapter *adapter) |
353 | { |
354 | struct tc_taprio_qopt_offload *qopt; |
355 | int i; |
356 | |
357 | qopt = kzalloc(struct_size(qopt, entries, 255), GFP_KERNEL); |
358 | if (!qopt) |
359 | return false; |
360 | for (i = 0; i < 255; i++) |
361 | qopt->entries[i].command = TC_TAPRIO_CMD_SET_GATES; |
362 | |
363 | qopt->cmd = TAPRIO_CMD_REPLACE; |
364 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
365 | qopt->cycle_time = 1500000; |
366 | qopt->cycle_time_extension = 0; |
367 | qopt->entries[0].gate_mask = 0x02; |
368 | qopt->entries[0].interval = 200000; |
369 | qopt->entries[1].gate_mask = 0x03; |
370 | qopt->entries[1].interval = 800000; |
371 | qopt->entries[2].gate_mask = 0x07; |
372 | qopt->entries[2].interval = 240000; |
373 | qopt->entries[3].gate_mask = 0x01; |
374 | qopt->entries[3].interval = 80000; |
375 | qopt->entries[4].gate_mask = 0x04; |
376 | qopt->entries[4].interval = 70000; |
377 | qopt->entries[5].gate_mask = 0x06; |
378 | qopt->entries[5].interval = 60000; |
379 | qopt->entries[6].gate_mask = 0x0F; |
380 | qopt->entries[6].interval = 50000; |
381 | qopt->num_entries = 7; |
382 | if (!run_taprio(adapter, qopt, ms: 100)) |
383 | goto failed; |
384 | |
385 | qopt->cmd = TAPRIO_CMD_REPLACE; |
386 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
387 | qopt->cycle_time = 411854; |
388 | qopt->cycle_time_extension = 0; |
389 | qopt->entries[0].gate_mask = 0x17; |
390 | qopt->entries[0].interval = 23842; |
391 | qopt->entries[1].gate_mask = 0x16; |
392 | qopt->entries[1].interval = 13482; |
393 | qopt->entries[2].gate_mask = 0x15; |
394 | qopt->entries[2].interval = 49428; |
395 | qopt->entries[3].gate_mask = 0x14; |
396 | qopt->entries[3].interval = 38189; |
397 | qopt->entries[4].gate_mask = 0x13; |
398 | qopt->entries[4].interval = 92321; |
399 | qopt->entries[5].gate_mask = 0x12; |
400 | qopt->entries[5].interval = 71239; |
401 | qopt->entries[6].gate_mask = 0x11; |
402 | qopt->entries[6].interval = 69932; |
403 | qopt->entries[7].gate_mask = 0x10; |
404 | qopt->entries[7].interval = 53421; |
405 | qopt->num_entries = 8; |
406 | if (!run_taprio(adapter, qopt, ms: 100)) |
407 | goto failed; |
408 | |
409 | qopt->cmd = TAPRIO_CMD_REPLACE; |
410 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
411 | delay_base_time(adapter, qopt, ms: 12); |
412 | qopt->cycle_time = 125000; |
413 | qopt->cycle_time_extension = 0; |
414 | qopt->entries[0].gate_mask = 0x27; |
415 | qopt->entries[0].interval = 15000; |
416 | qopt->entries[1].gate_mask = 0x26; |
417 | qopt->entries[1].interval = 15000; |
418 | qopt->entries[2].gate_mask = 0x25; |
419 | qopt->entries[2].interval = 12500; |
420 | qopt->entries[3].gate_mask = 0x24; |
421 | qopt->entries[3].interval = 17500; |
422 | qopt->entries[4].gate_mask = 0x23; |
423 | qopt->entries[4].interval = 10000; |
424 | qopt->entries[5].gate_mask = 0x22; |
425 | qopt->entries[5].interval = 11000; |
426 | qopt->entries[6].gate_mask = 0x21; |
427 | qopt->entries[6].interval = 9000; |
428 | qopt->entries[7].gate_mask = 0x20; |
429 | qopt->entries[7].interval = 10000; |
430 | qopt->entries[8].gate_mask = 0x20; |
431 | qopt->entries[8].interval = 12500; |
432 | qopt->entries[9].gate_mask = 0x20; |
433 | qopt->entries[9].interval = 12500; |
434 | qopt->num_entries = 10; |
435 | if (!run_taprio(adapter, qopt, ms: 100)) |
436 | goto failed; |
437 | |
438 | kfree(objp: qopt); |
439 | |
440 | return true; |
441 | |
442 | failed: |
443 | disable_taprio(adapter); |
444 | kfree(objp: qopt); |
445 | |
446 | return false; |
447 | } |
448 | |
449 | static bool tsnep_test_taprio_change(struct tsnep_adapter *adapter) |
450 | { |
451 | struct tc_taprio_qopt_offload *qopt; |
452 | int i; |
453 | |
454 | qopt = kzalloc(struct_size(qopt, entries, 255), GFP_KERNEL); |
455 | if (!qopt) |
456 | return false; |
457 | for (i = 0; i < 255; i++) |
458 | qopt->entries[i].command = TC_TAPRIO_CMD_SET_GATES; |
459 | |
460 | qopt->cmd = TAPRIO_CMD_REPLACE; |
461 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
462 | qopt->cycle_time = 100000; |
463 | qopt->cycle_time_extension = 0; |
464 | qopt->entries[0].gate_mask = 0x30; |
465 | qopt->entries[0].interval = 20000; |
466 | qopt->entries[1].gate_mask = 0x31; |
467 | qopt->entries[1].interval = 80000; |
468 | qopt->num_entries = 2; |
469 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
470 | goto failed; |
471 | |
472 | /* change to identical */ |
473 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
474 | goto failed; |
475 | delay_base_time(adapter, qopt, ms: 17); |
476 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
477 | goto failed; |
478 | |
479 | /* change to same cycle time */ |
480 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
481 | qopt->entries[0].gate_mask = 0x42; |
482 | qopt->entries[1].gate_mask = 0x43; |
483 | delay_base_time(adapter, qopt, ms: 2); |
484 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
485 | goto failed; |
486 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
487 | qopt->entries[0].gate_mask = 0x54; |
488 | qopt->entries[0].interval = 33333; |
489 | qopt->entries[1].gate_mask = 0x55; |
490 | qopt->entries[1].interval = 66667; |
491 | delay_base_time(adapter, qopt, ms: 23); |
492 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
493 | goto failed; |
494 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
495 | qopt->entries[0].gate_mask = 0x66; |
496 | qopt->entries[0].interval = 50000; |
497 | qopt->entries[1].gate_mask = 0x67; |
498 | qopt->entries[1].interval = 25000; |
499 | qopt->entries[2].gate_mask = 0x68; |
500 | qopt->entries[2].interval = 25000; |
501 | qopt->num_entries = 3; |
502 | delay_base_time(adapter, qopt, ms: 11); |
503 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
504 | goto failed; |
505 | |
506 | /* change to multiple of cycle time */ |
507 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
508 | qopt->cycle_time = 200000; |
509 | qopt->entries[0].gate_mask = 0x79; |
510 | qopt->entries[0].interval = 50000; |
511 | qopt->entries[1].gate_mask = 0x7A; |
512 | qopt->entries[1].interval = 150000; |
513 | qopt->num_entries = 2; |
514 | delay_base_time(adapter, qopt, ms: 11); |
515 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
516 | goto failed; |
517 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
518 | qopt->cycle_time = 1000000; |
519 | qopt->entries[0].gate_mask = 0x7B; |
520 | qopt->entries[0].interval = 125000; |
521 | qopt->entries[1].gate_mask = 0x7C; |
522 | qopt->entries[1].interval = 250000; |
523 | qopt->entries[2].gate_mask = 0x7D; |
524 | qopt->entries[2].interval = 375000; |
525 | qopt->entries[3].gate_mask = 0x7E; |
526 | qopt->entries[3].interval = 250000; |
527 | qopt->num_entries = 4; |
528 | delay_base_time(adapter, qopt, ms: 3); |
529 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
530 | goto failed; |
531 | |
532 | /* change to shorter cycle time */ |
533 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
534 | qopt->cycle_time = 333333; |
535 | qopt->entries[0].gate_mask = 0x8F; |
536 | qopt->entries[0].interval = 166666; |
537 | qopt->entries[1].gate_mask = 0x80; |
538 | qopt->entries[1].interval = 166667; |
539 | qopt->num_entries = 2; |
540 | delay_base_time(adapter, qopt, ms: 11); |
541 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
542 | goto failed; |
543 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
544 | qopt->cycle_time = 62500; |
545 | qopt->entries[0].gate_mask = 0x81; |
546 | qopt->entries[0].interval = 31250; |
547 | qopt->entries[1].gate_mask = 0x82; |
548 | qopt->entries[1].interval = 15625; |
549 | qopt->entries[2].gate_mask = 0x83; |
550 | qopt->entries[2].interval = 15625; |
551 | qopt->num_entries = 3; |
552 | delay_base_time(adapter, qopt, ms: 1); |
553 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
554 | goto failed; |
555 | |
556 | /* change to longer cycle time */ |
557 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
558 | qopt->cycle_time = 400000; |
559 | qopt->entries[0].gate_mask = 0x84; |
560 | qopt->entries[0].interval = 100000; |
561 | qopt->entries[1].gate_mask = 0x85; |
562 | qopt->entries[1].interval = 100000; |
563 | qopt->entries[2].gate_mask = 0x86; |
564 | qopt->entries[2].interval = 100000; |
565 | qopt->entries[3].gate_mask = 0x87; |
566 | qopt->entries[3].interval = 100000; |
567 | qopt->num_entries = 4; |
568 | delay_base_time(adapter, qopt, ms: 7); |
569 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
570 | goto failed; |
571 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
572 | qopt->cycle_time = 1700000; |
573 | qopt->entries[0].gate_mask = 0x88; |
574 | qopt->entries[0].interval = 200000; |
575 | qopt->entries[1].gate_mask = 0x89; |
576 | qopt->entries[1].interval = 300000; |
577 | qopt->entries[2].gate_mask = 0x8A; |
578 | qopt->entries[2].interval = 600000; |
579 | qopt->entries[3].gate_mask = 0x8B; |
580 | qopt->entries[3].interval = 100000; |
581 | qopt->entries[4].gate_mask = 0x8C; |
582 | qopt->entries[4].interval = 500000; |
583 | qopt->num_entries = 5; |
584 | delay_base_time(adapter, qopt, ms: 6); |
585 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
586 | goto failed; |
587 | |
588 | if (!disable_taprio(adapter)) |
589 | goto failed; |
590 | |
591 | kfree(objp: qopt); |
592 | |
593 | return true; |
594 | |
595 | failed: |
596 | disable_taprio(adapter); |
597 | kfree(objp: qopt); |
598 | |
599 | return false; |
600 | } |
601 | |
602 | static bool tsnep_test_taprio_extension(struct tsnep_adapter *adapter) |
603 | { |
604 | struct tc_taprio_qopt_offload *qopt; |
605 | int i; |
606 | |
607 | qopt = kzalloc(struct_size(qopt, entries, 255), GFP_KERNEL); |
608 | if (!qopt) |
609 | return false; |
610 | for (i = 0; i < 255; i++) |
611 | qopt->entries[i].command = TC_TAPRIO_CMD_SET_GATES; |
612 | |
613 | qopt->cmd = TAPRIO_CMD_REPLACE; |
614 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
615 | qopt->cycle_time = 100000; |
616 | qopt->cycle_time_extension = 50000; |
617 | qopt->entries[0].gate_mask = 0x90; |
618 | qopt->entries[0].interval = 20000; |
619 | qopt->entries[1].gate_mask = 0x91; |
620 | qopt->entries[1].interval = 80000; |
621 | qopt->num_entries = 2; |
622 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
623 | goto failed; |
624 | |
625 | /* change to different phase */ |
626 | qopt->base_time = ktime_set(secs: 0, nsecs: 50000); |
627 | qopt->entries[0].gate_mask = 0x92; |
628 | qopt->entries[0].interval = 33000; |
629 | qopt->entries[1].gate_mask = 0x93; |
630 | qopt->entries[1].interval = 67000; |
631 | qopt->num_entries = 2; |
632 | delay_base_time(adapter, qopt, ms: 2); |
633 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
634 | goto failed; |
635 | |
636 | /* change to different phase and longer cycle time */ |
637 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
638 | qopt->cycle_time = 1000000; |
639 | qopt->cycle_time_extension = 700000; |
640 | qopt->entries[0].gate_mask = 0x94; |
641 | qopt->entries[0].interval = 400000; |
642 | qopt->entries[1].gate_mask = 0x95; |
643 | qopt->entries[1].interval = 600000; |
644 | qopt->num_entries = 2; |
645 | delay_base_time(adapter, qopt, ms: 7); |
646 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
647 | goto failed; |
648 | qopt->base_time = ktime_set(secs: 0, nsecs: 700000); |
649 | qopt->cycle_time = 2000000; |
650 | qopt->cycle_time_extension = 1900000; |
651 | qopt->entries[0].gate_mask = 0x96; |
652 | qopt->entries[0].interval = 400000; |
653 | qopt->entries[1].gate_mask = 0x97; |
654 | qopt->entries[1].interval = 1600000; |
655 | qopt->num_entries = 2; |
656 | delay_base_time(adapter, qopt, ms: 9); |
657 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
658 | goto failed; |
659 | |
660 | /* change to different phase and shorter cycle time */ |
661 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
662 | qopt->cycle_time = 1500000; |
663 | qopt->cycle_time_extension = 700000; |
664 | qopt->entries[0].gate_mask = 0x98; |
665 | qopt->entries[0].interval = 400000; |
666 | qopt->entries[1].gate_mask = 0x99; |
667 | qopt->entries[1].interval = 600000; |
668 | qopt->entries[2].gate_mask = 0x9A; |
669 | qopt->entries[2].interval = 500000; |
670 | qopt->num_entries = 3; |
671 | delay_base_time(adapter, qopt, ms: 3); |
672 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
673 | goto failed; |
674 | qopt->base_time = ktime_set(secs: 0, nsecs: 100000); |
675 | qopt->cycle_time = 500000; |
676 | qopt->cycle_time_extension = 300000; |
677 | qopt->entries[0].gate_mask = 0x9B; |
678 | qopt->entries[0].interval = 150000; |
679 | qopt->entries[1].gate_mask = 0x9C; |
680 | qopt->entries[1].interval = 350000; |
681 | qopt->num_entries = 2; |
682 | delay_base_time(adapter, qopt, ms: 9); |
683 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
684 | goto failed; |
685 | |
686 | /* change to different cycle time */ |
687 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
688 | qopt->cycle_time = 1000000; |
689 | qopt->cycle_time_extension = 700000; |
690 | qopt->entries[0].gate_mask = 0xAD; |
691 | qopt->entries[0].interval = 400000; |
692 | qopt->entries[1].gate_mask = 0xAE; |
693 | qopt->entries[1].interval = 300000; |
694 | qopt->entries[2].gate_mask = 0xAF; |
695 | qopt->entries[2].interval = 300000; |
696 | qopt->num_entries = 3; |
697 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
698 | goto failed; |
699 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
700 | qopt->cycle_time = 400000; |
701 | qopt->cycle_time_extension = 100000; |
702 | qopt->entries[0].gate_mask = 0xA0; |
703 | qopt->entries[0].interval = 200000; |
704 | qopt->entries[1].gate_mask = 0xA1; |
705 | qopt->entries[1].interval = 200000; |
706 | qopt->num_entries = 2; |
707 | delay_base_time(adapter, qopt, ms: 19); |
708 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
709 | goto failed; |
710 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
711 | qopt->cycle_time = 500000; |
712 | qopt->cycle_time_extension = 499999; |
713 | qopt->entries[0].gate_mask = 0xB2; |
714 | qopt->entries[0].interval = 100000; |
715 | qopt->entries[1].gate_mask = 0xB3; |
716 | qopt->entries[1].interval = 100000; |
717 | qopt->entries[2].gate_mask = 0xB4; |
718 | qopt->entries[2].interval = 100000; |
719 | qopt->entries[3].gate_mask = 0xB5; |
720 | qopt->entries[3].interval = 200000; |
721 | qopt->num_entries = 4; |
722 | delay_base_time(adapter, qopt, ms: 19); |
723 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
724 | goto failed; |
725 | qopt->base_time = ktime_set(secs: 0, nsecs: 0); |
726 | qopt->cycle_time = 6000000; |
727 | qopt->cycle_time_extension = 5999999; |
728 | qopt->entries[0].gate_mask = 0xC6; |
729 | qopt->entries[0].interval = 1000000; |
730 | qopt->entries[1].gate_mask = 0xC7; |
731 | qopt->entries[1].interval = 1000000; |
732 | qopt->entries[2].gate_mask = 0xC8; |
733 | qopt->entries[2].interval = 1000000; |
734 | qopt->entries[3].gate_mask = 0xC9; |
735 | qopt->entries[3].interval = 1500000; |
736 | qopt->entries[4].gate_mask = 0xCA; |
737 | qopt->entries[4].interval = 1500000; |
738 | qopt->num_entries = 5; |
739 | delay_base_time(adapter, qopt, ms: 1); |
740 | if (!enable_check_taprio(adapter, qopt, ms: 100)) |
741 | goto failed; |
742 | |
743 | if (!disable_taprio(adapter)) |
744 | goto failed; |
745 | |
746 | kfree(objp: qopt); |
747 | |
748 | return true; |
749 | |
750 | failed: |
751 | disable_taprio(adapter); |
752 | kfree(objp: qopt); |
753 | |
754 | return false; |
755 | } |
756 | |
757 | int tsnep_ethtool_get_test_count(void) |
758 | { |
759 | return TSNEP_TEST_COUNT; |
760 | } |
761 | |
762 | void tsnep_ethtool_get_test_strings(u8 *data) |
763 | { |
764 | memcpy(data, tsnep_test_strings, sizeof(tsnep_test_strings)); |
765 | } |
766 | |
767 | void tsnep_ethtool_self_test(struct net_device *netdev, |
768 | struct ethtool_test *eth_test, u64 *data) |
769 | { |
770 | struct tsnep_adapter *adapter = netdev_priv(dev: netdev); |
771 | |
772 | eth_test->len = TSNEP_TEST_COUNT; |
773 | |
774 | if (eth_test->flags != ETH_TEST_FL_OFFLINE) { |
775 | /* no tests are done online */ |
776 | data[TSNEP_TEST_ENABLE] = 0; |
777 | data[TSNEP_TEST_TAPRIO] = 0; |
778 | data[TSNEP_TEST_TAPRIO_CHANGE] = 0; |
779 | data[TSNEP_TEST_TAPRIO_EXTENSION] = 0; |
780 | |
781 | return; |
782 | } |
783 | |
784 | if (tsnep_test_gc_enable(adapter)) { |
785 | data[TSNEP_TEST_ENABLE] = 0; |
786 | } else { |
787 | eth_test->flags |= ETH_TEST_FL_FAILED; |
788 | data[TSNEP_TEST_ENABLE] = 1; |
789 | } |
790 | |
791 | if (tsnep_test_taprio(adapter)) { |
792 | data[TSNEP_TEST_TAPRIO] = 0; |
793 | } else { |
794 | eth_test->flags |= ETH_TEST_FL_FAILED; |
795 | data[TSNEP_TEST_TAPRIO] = 1; |
796 | } |
797 | |
798 | if (tsnep_test_taprio_change(adapter)) { |
799 | data[TSNEP_TEST_TAPRIO_CHANGE] = 0; |
800 | } else { |
801 | eth_test->flags |= ETH_TEST_FL_FAILED; |
802 | data[TSNEP_TEST_TAPRIO_CHANGE] = 1; |
803 | } |
804 | |
805 | if (tsnep_test_taprio_extension(adapter)) { |
806 | data[TSNEP_TEST_TAPRIO_EXTENSION] = 0; |
807 | } else { |
808 | eth_test->flags |= ETH_TEST_FL_FAILED; |
809 | data[TSNEP_TEST_TAPRIO_EXTENSION] = 1; |
810 | } |
811 | } |
812 | |