1// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright (c) 2023 Intel Corporation. */
3#define dev_fmt(fmt) "Telemetry debugfs: " fmt
4
5#include <linux/atomic.h>
6#include <linux/debugfs.h>
7#include <linux/dev_printk.h>
8#include <linux/dcache.h>
9#include <linux/file.h>
10#include <linux/kernel.h>
11#include <linux/math64.h>
12#include <linux/mutex.h>
13#include <linux/seq_file.h>
14#include <linux/slab.h>
15#include <linux/units.h>
16
17#include "adf_accel_devices.h"
18#include "adf_cfg_strings.h"
19#include "adf_telemetry.h"
20#include "adf_tl_debugfs.h"
21
22#define TL_VALUE_MIN_PADDING 20
23#define TL_KEY_MIN_PADDING 23
24#define TL_RP_SRV_UNKNOWN "Unknown"
25
26static int tl_collect_values_u32(struct adf_telemetry *telemetry,
27 size_t counter_offset, u64 *arr)
28{
29 unsigned int samples, hb_idx, i;
30 u32 *regs_hist_buff;
31 u32 counter_val;
32
33 samples = min(telemetry->msg_cnt, telemetry->hbuffs);
34 hb_idx = telemetry->hb_num + telemetry->hbuffs - samples;
35
36 mutex_lock(&telemetry->regs_hist_lock);
37
38 for (i = 0; i < samples; i++) {
39 regs_hist_buff = telemetry->regs_hist_buff[hb_idx % telemetry->hbuffs];
40 counter_val = regs_hist_buff[counter_offset / sizeof(counter_val)];
41 arr[i] = counter_val;
42 hb_idx++;
43 }
44
45 mutex_unlock(lock: &telemetry->regs_hist_lock);
46
47 return samples;
48}
49
50static int tl_collect_values_u64(struct adf_telemetry *telemetry,
51 size_t counter_offset, u64 *arr)
52{
53 unsigned int samples, hb_idx, i;
54 u64 *regs_hist_buff;
55 u64 counter_val;
56
57 samples = min(telemetry->msg_cnt, telemetry->hbuffs);
58 hb_idx = telemetry->hb_num + telemetry->hbuffs - samples;
59
60 mutex_lock(&telemetry->regs_hist_lock);
61
62 for (i = 0; i < samples; i++) {
63 regs_hist_buff = telemetry->regs_hist_buff[hb_idx % telemetry->hbuffs];
64 counter_val = regs_hist_buff[counter_offset / sizeof(counter_val)];
65 arr[i] = counter_val;
66 hb_idx++;
67 }
68
69 mutex_unlock(lock: &telemetry->regs_hist_lock);
70
71 return samples;
72}
73
74/**
75 * avg_array() - Return average of values within an array.
76 * @array: Array of values.
77 * @len: Number of elements.
78 *
79 * This algorithm computes average of an array without running into overflow.
80 *
81 * Return: average of values.
82 */
83#define avg_array(array, len) ( \
84{ \
85 typeof(&(array)[0]) _array = (array); \
86 __unqual_scalar_typeof(_array[0]) _x = 0; \
87 __unqual_scalar_typeof(_array[0]) _y = 0; \
88 __unqual_scalar_typeof(_array[0]) _a, _b; \
89 typeof(len) _len = (len); \
90 size_t _i; \
91 \
92 for (_i = 0; _i < _len; _i++) { \
93 _a = _array[_i]; \
94 _b = do_div(_a, _len); \
95 _x += _a; \
96 if (_y >= _len - _b) { \
97 _x++; \
98 _y -= _len - _b; \
99 } else { \
100 _y += _b; \
101 } \
102 } \
103 do_div(_y, _len); \
104 (_x + _y); \
105})
106
107/* Calculation function for simple counter. */
108static int tl_calc_count(struct adf_telemetry *telemetry,
109 const struct adf_tl_dbg_counter *ctr,
110 struct adf_tl_dbg_aggr_values *vals)
111{
112 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
113 u64 *hist_vals;
114 int sample_cnt;
115 int ret = 0;
116
117 hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals),
118 GFP_KERNEL);
119 if (!hist_vals)
120 return -ENOMEM;
121
122 memset(vals, 0, sizeof(*vals));
123 sample_cnt = tl_collect_values_u32(telemetry, counter_offset: ctr->offset1, arr: hist_vals);
124 if (!sample_cnt)
125 goto out_free_hist_vals;
126
127 vals->curr = hist_vals[sample_cnt - 1];
128 vals->min = min_array(hist_vals, sample_cnt);
129 vals->max = max_array(hist_vals, sample_cnt);
130 vals->avg = avg_array(hist_vals, sample_cnt);
131
132out_free_hist_vals:
133 kfree(objp: hist_vals);
134 return ret;
135}
136
137/* Convert CPP bus cycles to ns. */
138static int tl_cycles_to_ns(struct adf_telemetry *telemetry,
139 const struct adf_tl_dbg_counter *ctr,
140 struct adf_tl_dbg_aggr_values *vals)
141{
142 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
143 u8 cpp_ns_per_cycle = tl_data->cpp_ns_per_cycle;
144 int ret;
145
146 ret = tl_calc_count(telemetry, ctr, vals);
147 if (ret)
148 return ret;
149
150 vals->curr *= cpp_ns_per_cycle;
151 vals->min *= cpp_ns_per_cycle;
152 vals->max *= cpp_ns_per_cycle;
153 vals->avg *= cpp_ns_per_cycle;
154
155 return 0;
156}
157
158/*
159 * Compute latency cumulative average with division of accumulated value
160 * by sample count. Returned value is in ns.
161 */
162static int tl_lat_acc_avg(struct adf_telemetry *telemetry,
163 const struct adf_tl_dbg_counter *ctr,
164 struct adf_tl_dbg_aggr_values *vals)
165{
166 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
167 u8 cpp_ns_per_cycle = tl_data->cpp_ns_per_cycle;
168 u8 num_hbuff = tl_data->num_hbuff;
169 int sample_cnt, i;
170 u64 *hist_vals;
171 u64 *hist_cnt;
172 int ret = 0;
173
174 hist_vals = kmalloc_array(num_hbuff, sizeof(*hist_vals), GFP_KERNEL);
175 if (!hist_vals)
176 return -ENOMEM;
177
178 hist_cnt = kmalloc_array(num_hbuff, sizeof(*hist_cnt), GFP_KERNEL);
179 if (!hist_cnt) {
180 ret = -ENOMEM;
181 goto out_free_hist_vals;
182 }
183
184 memset(vals, 0, sizeof(*vals));
185 sample_cnt = tl_collect_values_u64(telemetry, counter_offset: ctr->offset1, arr: hist_vals);
186 if (!sample_cnt)
187 goto out_free_hist_cnt;
188
189 tl_collect_values_u32(telemetry, counter_offset: ctr->offset2, arr: hist_cnt);
190
191 for (i = 0; i < sample_cnt; i++) {
192 /* Avoid division by 0 if count is 0. */
193 if (hist_cnt[i])
194 hist_vals[i] = div_u64(dividend: hist_vals[i] * cpp_ns_per_cycle,
195 divisor: hist_cnt[i]);
196 else
197 hist_vals[i] = 0;
198 }
199
200 vals->curr = hist_vals[sample_cnt - 1];
201 vals->min = min_array(hist_vals, sample_cnt);
202 vals->max = max_array(hist_vals, sample_cnt);
203 vals->avg = avg_array(hist_vals, sample_cnt);
204
205out_free_hist_cnt:
206 kfree(objp: hist_cnt);
207out_free_hist_vals:
208 kfree(objp: hist_vals);
209 return ret;
210}
211
212/* Convert HW raw bandwidth units to Mbps. */
213static int tl_bw_hw_units_to_mbps(struct adf_telemetry *telemetry,
214 const struct adf_tl_dbg_counter *ctr,
215 struct adf_tl_dbg_aggr_values *vals)
216{
217 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
218 u16 bw_hw_2_bits = tl_data->bw_units_to_bytes * BITS_PER_BYTE;
219 u64 *hist_vals;
220 int sample_cnt;
221 int ret = 0;
222
223 hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals),
224 GFP_KERNEL);
225 if (!hist_vals)
226 return -ENOMEM;
227
228 memset(vals, 0, sizeof(*vals));
229 sample_cnt = tl_collect_values_u32(telemetry, counter_offset: ctr->offset1, arr: hist_vals);
230 if (!sample_cnt)
231 goto out_free_hist_vals;
232
233 vals->curr = div_u64(dividend: hist_vals[sample_cnt - 1] * bw_hw_2_bits, MEGA);
234 vals->min = div_u64(min_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA);
235 vals->max = div_u64(max_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA);
236 vals->avg = div_u64(avg_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA);
237
238out_free_hist_vals:
239 kfree(objp: hist_vals);
240 return ret;
241}
242
243static void tl_seq_printf_counter(struct adf_telemetry *telemetry,
244 struct seq_file *s, const char *name,
245 struct adf_tl_dbg_aggr_values *vals)
246{
247 seq_printf(m: s, fmt: "%-*s", TL_KEY_MIN_PADDING, name);
248 seq_printf(m: s, fmt: "%*llu", TL_VALUE_MIN_PADDING, vals->curr);
249 if (atomic_read(v: &telemetry->state) > 1) {
250 seq_printf(m: s, fmt: "%*llu", TL_VALUE_MIN_PADDING, vals->min);
251 seq_printf(m: s, fmt: "%*llu", TL_VALUE_MIN_PADDING, vals->max);
252 seq_printf(m: s, fmt: "%*llu", TL_VALUE_MIN_PADDING, vals->avg);
253 }
254 seq_puts(m: s, s: "\n");
255}
256
257static int tl_calc_and_print_counter(struct adf_telemetry *telemetry,
258 struct seq_file *s,
259 const struct adf_tl_dbg_counter *ctr,
260 const char *name)
261{
262 const char *counter_name = name ? name : ctr->name;
263 enum adf_tl_counter_type type = ctr->type;
264 struct adf_tl_dbg_aggr_values vals;
265 int ret;
266
267 switch (type) {
268 case ADF_TL_SIMPLE_COUNT:
269 ret = tl_calc_count(telemetry, ctr, vals: &vals);
270 break;
271 case ADF_TL_COUNTER_NS:
272 ret = tl_cycles_to_ns(telemetry, ctr, vals: &vals);
273 break;
274 case ADF_TL_COUNTER_NS_AVG:
275 ret = tl_lat_acc_avg(telemetry, ctr, vals: &vals);
276 break;
277 case ADF_TL_COUNTER_MBPS:
278 ret = tl_bw_hw_units_to_mbps(telemetry, ctr, vals: &vals);
279 break;
280 default:
281 return -EINVAL;
282 }
283
284 if (ret)
285 return ret;
286
287 tl_seq_printf_counter(telemetry, s, name: counter_name, vals: &vals);
288
289 return 0;
290}
291
292static int tl_print_sl_counter(struct adf_telemetry *telemetry,
293 const struct adf_tl_dbg_counter *ctr,
294 struct seq_file *s, u8 cnt_id)
295{
296 size_t sl_regs_sz = GET_TL_DATA(telemetry->accel_dev).slice_reg_sz;
297 struct adf_tl_dbg_counter slice_ctr;
298 size_t offset_inc = cnt_id * sl_regs_sz;
299 char cnt_name[MAX_COUNT_NAME_SIZE];
300
301 snprintf(buf: cnt_name, MAX_COUNT_NAME_SIZE, fmt: "%s%d", ctr->name, cnt_id);
302 slice_ctr = *ctr;
303 slice_ctr.offset1 += offset_inc;
304
305 return tl_calc_and_print_counter(telemetry, s, ctr: &slice_ctr, name: cnt_name);
306}
307
308static int tl_calc_and_print_sl_counters(struct adf_accel_dev *accel_dev,
309 struct seq_file *s, u8 cnt_type, u8 cnt_id)
310{
311 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
312 struct adf_telemetry *telemetry = accel_dev->telemetry;
313 const struct adf_tl_dbg_counter *sl_tl_util_counters;
314 const struct adf_tl_dbg_counter *sl_tl_exec_counters;
315 const struct adf_tl_dbg_counter *ctr;
316 int ret;
317
318 sl_tl_util_counters = tl_data->sl_util_counters;
319 sl_tl_exec_counters = tl_data->sl_exec_counters;
320
321 ctr = &sl_tl_util_counters[cnt_type];
322
323 ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id);
324 if (ret) {
325 dev_notice(&GET_DEV(accel_dev),
326 "invalid slice utilization counter type\n");
327 return ret;
328 }
329
330 ctr = &sl_tl_exec_counters[cnt_type];
331
332 ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id);
333 if (ret) {
334 dev_notice(&GET_DEV(accel_dev),
335 "invalid slice execution counter type\n");
336 return ret;
337 }
338
339 return 0;
340}
341
342static int tl_print_cmdq_counter(struct adf_telemetry *telemetry,
343 const struct adf_tl_dbg_counter *ctr,
344 struct seq_file *s, u8 cnt_id, u8 counter)
345{
346 size_t cmdq_regs_sz = GET_TL_DATA(telemetry->accel_dev).cmdq_reg_sz;
347 size_t offset_inc = cnt_id * cmdq_regs_sz;
348 struct adf_tl_dbg_counter slice_ctr;
349 char cnt_name[MAX_COUNT_NAME_SIZE];
350
351 slice_ctr = *(ctr + counter);
352 slice_ctr.offset1 += offset_inc;
353 snprintf(buf: cnt_name, MAX_COUNT_NAME_SIZE, fmt: "%s%d", slice_ctr.name, cnt_id);
354
355 return tl_calc_and_print_counter(telemetry, s, ctr: &slice_ctr, name: cnt_name);
356}
357
358static int tl_calc_and_print_cmdq_counters(struct adf_accel_dev *accel_dev,
359 struct seq_file *s, u8 cnt_type,
360 u8 cnt_id)
361{
362 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
363 struct adf_telemetry *telemetry = accel_dev->telemetry;
364 const struct adf_tl_dbg_counter **cmdq_tl_counters;
365 const struct adf_tl_dbg_counter *ctr;
366 u8 counter;
367 int ret;
368
369 cmdq_tl_counters = tl_data->cmdq_counters;
370 ctr = cmdq_tl_counters[cnt_type];
371
372 for (counter = 0; counter < tl_data->num_cmdq_counters; counter++) {
373 ret = tl_print_cmdq_counter(telemetry, ctr, s, cnt_id, counter);
374 if (ret) {
375 dev_notice(&GET_DEV(accel_dev),
376 "invalid slice utilization counter type\n");
377 return ret;
378 }
379 }
380
381 return 0;
382}
383
384static void tl_print_msg_cnt(struct seq_file *s, u32 msg_cnt)
385{
386 seq_printf(m: s, fmt: "%-*s", TL_KEY_MIN_PADDING, SNAPSHOT_CNT_MSG);
387 seq_printf(m: s, fmt: "%*u\n", TL_VALUE_MIN_PADDING, msg_cnt);
388}
389
390static int tl_print_dev_data(struct adf_accel_dev *accel_dev,
391 struct seq_file *s)
392{
393 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
394 struct adf_telemetry *telemetry = accel_dev->telemetry;
395 const struct adf_tl_dbg_counter *dev_tl_counters;
396 u8 num_dev_counters = tl_data->num_dev_counters;
397 u8 *cmdq_cnt = (u8 *)&telemetry->cmdq_cnt;
398 u8 *sl_cnt = (u8 *)&telemetry->slice_cnt;
399 const struct adf_tl_dbg_counter *ctr;
400 unsigned int i;
401 int ret;
402 u8 j;
403
404 if (!atomic_read(v: &telemetry->state)) {
405 dev_info(&GET_DEV(accel_dev), "not enabled\n");
406 return -EPERM;
407 }
408
409 dev_tl_counters = tl_data->dev_counters;
410
411 tl_print_msg_cnt(s, msg_cnt: telemetry->msg_cnt);
412
413 /* Print device level telemetry. */
414 for (i = 0; i < num_dev_counters; i++) {
415 ctr = &dev_tl_counters[i];
416 ret = tl_calc_and_print_counter(telemetry, s, ctr, NULL);
417 if (ret) {
418 dev_notice(&GET_DEV(accel_dev),
419 "invalid counter type\n");
420 return ret;
421 }
422 }
423
424 /* Print per slice telemetry. */
425 for (i = 0; i < ADF_TL_SL_CNT_COUNT; i++) {
426 for (j = 0; j < sl_cnt[i]; j++) {
427 ret = tl_calc_and_print_sl_counters(accel_dev, s, cnt_type: i, cnt_id: j);
428 if (ret)
429 return ret;
430 }
431 }
432
433 /* Print per command queue telemetry. */
434 for (i = 0; i < ADF_TL_SL_CNT_COUNT; i++) {
435 for (j = 0; j < cmdq_cnt[i]; j++) {
436 ret = tl_calc_and_print_cmdq_counters(accel_dev, s, cnt_type: i, cnt_id: j);
437 if (ret)
438 return ret;
439 }
440 }
441
442 return 0;
443}
444
445static int tl_dev_data_show(struct seq_file *s, void *unused)
446{
447 struct adf_accel_dev *accel_dev = s->private;
448
449 if (!accel_dev)
450 return -EINVAL;
451
452 return tl_print_dev_data(accel_dev, s);
453}
454DEFINE_SHOW_ATTRIBUTE(tl_dev_data);
455
456static int tl_control_show(struct seq_file *s, void *unused)
457{
458 struct adf_accel_dev *accel_dev = s->private;
459
460 if (!accel_dev)
461 return -EINVAL;
462
463 seq_printf(m: s, fmt: "%d\n", atomic_read(v: &accel_dev->telemetry->state));
464
465 return 0;
466}
467
468static ssize_t tl_control_write(struct file *file, const char __user *userbuf,
469 size_t count, loff_t *ppos)
470{
471 struct seq_file *seq_f = file->private_data;
472 struct adf_accel_dev *accel_dev;
473 struct adf_telemetry *telemetry;
474 struct adf_tl_hw_data *tl_data;
475 struct device *dev;
476 u32 input;
477 int ret;
478
479 accel_dev = seq_f->private;
480 if (!accel_dev)
481 return -EINVAL;
482
483 tl_data = &GET_TL_DATA(accel_dev);
484 telemetry = accel_dev->telemetry;
485 dev = &GET_DEV(accel_dev);
486
487 mutex_lock(&telemetry->wr_lock);
488
489 ret = kstrtou32_from_user(s: userbuf, count, base: 10, res: &input);
490 if (ret)
491 goto unlock_and_exit;
492
493 if (input > tl_data->num_hbuff) {
494 dev_info(dev, "invalid control input\n");
495 ret = -EINVAL;
496 goto unlock_and_exit;
497 }
498
499 /* If input is 0, just stop telemetry. */
500 if (!input) {
501 ret = adf_tl_halt(accel_dev);
502 if (!ret)
503 ret = count;
504
505 goto unlock_and_exit;
506 }
507
508 /* If TL is already enabled, stop it. */
509 if (atomic_read(v: &telemetry->state)) {
510 dev_info(dev, "already enabled, restarting.\n");
511 ret = adf_tl_halt(accel_dev);
512 if (ret)
513 goto unlock_and_exit;
514 }
515
516 ret = adf_tl_run(accel_dev, state: input);
517 if (ret)
518 goto unlock_and_exit;
519
520 ret = count;
521
522unlock_and_exit:
523 mutex_unlock(lock: &telemetry->wr_lock);
524 return ret;
525}
526DEFINE_SHOW_STORE_ATTRIBUTE(tl_control);
527
528static int adf_tl_dbg_change_rp_index(struct adf_accel_dev *accel_dev,
529 unsigned int new_rp_num,
530 unsigned int rp_regs_index)
531{
532 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
533 struct adf_telemetry *telemetry = accel_dev->telemetry;
534 struct device *dev = &GET_DEV(accel_dev);
535 unsigned int i;
536 u8 curr_state;
537 int ret;
538
539 if (new_rp_num >= hw_data->num_rps) {
540 dev_info(dev, "invalid Ring Pair number selected\n");
541 return -EINVAL;
542 }
543
544 for (i = 0; i < hw_data->tl_data.max_rp; i++) {
545 if (telemetry->rp_num_indexes[i] == new_rp_num) {
546 dev_info(dev, "RP nr: %d is already selected in slot rp_%c_data\n",
547 new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(i));
548 return 0;
549 }
550 }
551
552 dev_dbg(dev, "selecting RP nr %u into slot rp_%c_data\n",
553 new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index));
554
555 curr_state = atomic_read(v: &telemetry->state);
556
557 if (curr_state) {
558 ret = adf_tl_halt(accel_dev);
559 if (ret)
560 return ret;
561
562 telemetry->rp_num_indexes[rp_regs_index] = new_rp_num;
563
564 ret = adf_tl_run(accel_dev, state: curr_state);
565 if (ret)
566 return ret;
567 } else {
568 telemetry->rp_num_indexes[rp_regs_index] = new_rp_num;
569 }
570
571 return 0;
572}
573
574static void tl_print_rp_srv(struct adf_accel_dev *accel_dev, struct seq_file *s,
575 u8 rp_idx)
576{
577 u32 banks_per_vf = GET_HW_DATA(accel_dev)->num_banks_per_vf;
578 enum adf_cfg_service_type svc;
579
580 seq_printf(m: s, fmt: "%-*s", TL_KEY_MIN_PADDING, RP_SERVICE_TYPE);
581
582 svc = GET_SRV_TYPE(accel_dev, rp_idx % banks_per_vf);
583 switch (svc) {
584 case COMP:
585 seq_printf(m: s, fmt: "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_DC);
586 break;
587 case SYM:
588 seq_printf(m: s, fmt: "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_SYM);
589 break;
590 case ASYM:
591 seq_printf(m: s, fmt: "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_ASYM);
592 break;
593 case DECOMP:
594 seq_printf(m: s, fmt: "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_DECOMP);
595 break;
596 default:
597 seq_printf(m: s, fmt: "%*s\n", TL_VALUE_MIN_PADDING, TL_RP_SRV_UNKNOWN);
598 break;
599 }
600}
601
602static int tl_print_rp_data(struct adf_accel_dev *accel_dev, struct seq_file *s,
603 u8 rp_regs_index)
604{
605 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
606 struct adf_telemetry *telemetry = accel_dev->telemetry;
607 const struct adf_tl_dbg_counter *rp_tl_counters;
608 u8 num_rp_counters = tl_data->num_rp_counters;
609 size_t rp_regs_sz = tl_data->rp_reg_sz;
610 struct adf_tl_dbg_counter ctr;
611 unsigned int i;
612 u8 rp_idx;
613 int ret;
614
615 if (!atomic_read(v: &telemetry->state)) {
616 dev_info(&GET_DEV(accel_dev), "not enabled\n");
617 return -EPERM;
618 }
619
620 rp_tl_counters = tl_data->rp_counters;
621 rp_idx = telemetry->rp_num_indexes[rp_regs_index];
622
623 if (rp_idx == ADF_TL_RP_REGS_DISABLED) {
624 dev_info(&GET_DEV(accel_dev), "no RP number selected in rp_%c_data\n",
625 ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index));
626 return -EPERM;
627 }
628
629 tl_print_msg_cnt(s, msg_cnt: telemetry->msg_cnt);
630 seq_printf(m: s, fmt: "%-*s", TL_KEY_MIN_PADDING, RP_NUM_INDEX);
631 seq_printf(m: s, fmt: "%*d\n", TL_VALUE_MIN_PADDING, rp_idx);
632 tl_print_rp_srv(accel_dev, s, rp_idx);
633
634 for (i = 0; i < num_rp_counters; i++) {
635 ctr = rp_tl_counters[i];
636 ctr.offset1 += rp_regs_sz * rp_regs_index;
637 ctr.offset2 += rp_regs_sz * rp_regs_index;
638 ret = tl_calc_and_print_counter(telemetry, s, ctr: &ctr, NULL);
639 if (ret) {
640 dev_dbg(&GET_DEV(accel_dev),
641 "invalid RP counter type\n");
642 return ret;
643 }
644 }
645
646 return 0;
647}
648
649static int tl_rp_data_show(struct seq_file *s, void *unused)
650{
651 struct adf_accel_dev *accel_dev = s->private;
652 u8 rp_regs_index;
653
654 if (!accel_dev)
655 return -EINVAL;
656
657 rp_regs_index = debugfs_get_aux_num(s->file);
658
659 return tl_print_rp_data(accel_dev, s, rp_regs_index);
660}
661
662static ssize_t tl_rp_data_write(struct file *file, const char __user *userbuf,
663 size_t count, loff_t *ppos)
664{
665 struct seq_file *seq_f = file->private_data;
666 struct adf_accel_dev *accel_dev;
667 struct adf_telemetry *telemetry;
668 unsigned int new_rp_num;
669 u8 rp_regs_index;
670 int ret;
671
672 accel_dev = seq_f->private;
673 if (!accel_dev)
674 return -EINVAL;
675
676 telemetry = accel_dev->telemetry;
677
678 mutex_lock(&telemetry->wr_lock);
679
680 rp_regs_index = debugfs_get_aux_num(file);
681
682 ret = kstrtou32_from_user(s: userbuf, count, base: 10, res: &new_rp_num);
683 if (ret)
684 goto unlock_and_exit;
685
686 ret = adf_tl_dbg_change_rp_index(accel_dev, new_rp_num, rp_regs_index);
687 if (ret)
688 goto unlock_and_exit;
689
690 ret = count;
691
692unlock_and_exit:
693 mutex_unlock(lock: &telemetry->wr_lock);
694 return ret;
695}
696DEFINE_SHOW_STORE_ATTRIBUTE(tl_rp_data);
697
698void adf_tl_dbgfs_add(struct adf_accel_dev *accel_dev)
699{
700 struct adf_telemetry *telemetry = accel_dev->telemetry;
701 struct dentry *parent = accel_dev->debugfs_dir;
702 u8 max_rp = GET_TL_DATA(accel_dev).max_rp;
703 char name[ADF_TL_RP_REGS_FNAME_SIZE];
704 struct dentry *dir;
705 unsigned int i;
706
707 if (!telemetry)
708 return;
709
710 dir = debugfs_create_dir(name: "telemetry", parent);
711 accel_dev->telemetry->dbg_dir = dir;
712 debugfs_create_file("device_data", 0444, dir, accel_dev, &tl_dev_data_fops);
713 debugfs_create_file("control", 0644, dir, accel_dev, &tl_control_fops);
714
715 for (i = 0; i < max_rp; i++) {
716 snprintf(buf: name, size: sizeof(name), ADF_TL_RP_REGS_FNAME,
717 ADF_TL_DBG_RP_ALPHA_INDEX(i));
718 debugfs_create_file_aux_num(name, 0644, dir, accel_dev, i,
719 &tl_rp_data_fops);
720 }
721}
722
723void adf_tl_dbgfs_rm(struct adf_accel_dev *accel_dev)
724{
725 struct adf_telemetry *telemetry = accel_dev->telemetry;
726 struct dentry *dbg_dir;
727
728 if (!telemetry)
729 return;
730
731 dbg_dir = telemetry->dbg_dir;
732
733 debugfs_remove_recursive(dentry: dbg_dir);
734
735 if (atomic_read(v: &telemetry->state))
736 adf_tl_halt(accel_dev);
737}
738

source code of linux/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c