1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2023 Intel Corporation. */
3 #define dev_fmt(fmt) "Telemetry debugfs: " fmt
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>
17 #include "adf_accel_devices.h"
18 #include "adf_cfg_strings.h"
19 #include "adf_telemetry.h"
20 #include "adf_tl_debugfs.h"
22 #define TL_VALUE_MIN_PADDING 20
23 #define TL_KEY_MIN_PADDING 23
24 #define TL_RP_SRV_UNKNOWN "Unknown"
26 static int tl_collect_values_u32(struct adf_telemetry *telemetry,
27 size_t counter_offset, u64 *arr)
29 unsigned int samples, hb_idx, i;
33 samples = min(telemetry->msg_cnt, telemetry->hbuffs);
34 hb_idx = telemetry->hb_num + telemetry->hbuffs - samples;
36 mutex_lock(&telemetry->regs_hist_lock);
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)];
45 mutex_unlock(&telemetry->regs_hist_lock);
50 static int tl_collect_values_u64(struct adf_telemetry *telemetry,
51 size_t counter_offset, u64 *arr)
53 unsigned int samples, hb_idx, i;
57 samples = min(telemetry->msg_cnt, telemetry->hbuffs);
58 hb_idx = telemetry->hb_num + telemetry->hbuffs - samples;
60 mutex_lock(&telemetry->regs_hist_lock);
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)];
69 mutex_unlock(&telemetry->regs_hist_lock);
75 * avg_array() - Return average of values within an array.
76 * @array: Array of values.
77 * @len: Number of elements.
79 * This algorithm computes average of an array without running into overflow.
81 * Return: average of values.
83 #define avg_array(array, len) ( \
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); \
92 for (_i = 0; _i < _len; _i++) { \
94 _b = do_div(_a, _len); \
96 if (_y >= _len - _b) { \
107 /* Calculation function for simple counter. */
108 static int tl_calc_count(struct adf_telemetry *telemetry,
109 const struct adf_tl_dbg_counter *ctr,
110 struct adf_tl_dbg_aggr_values *vals)
112 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
117 hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals),
122 memset(vals, 0, sizeof(*vals));
123 sample_cnt = tl_collect_values_u32(telemetry, ctr->offset1, hist_vals);
125 goto out_free_hist_vals;
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);
137 /* Convert CPP bus cycles to ns. */
138 static 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)
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;
146 ret = tl_calc_count(telemetry, ctr, vals);
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;
159 * Compute latency cumulative average with division of accumulated value
160 * by sample count. Returned value is in ns.
162 static 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)
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;
174 hist_vals = kmalloc_array(num_hbuff, sizeof(*hist_vals), GFP_KERNEL);
178 hist_cnt = kmalloc_array(num_hbuff, sizeof(*hist_cnt), GFP_KERNEL);
181 goto out_free_hist_vals;
184 memset(vals, 0, sizeof(*vals));
185 sample_cnt = tl_collect_values_u64(telemetry, ctr->offset1, hist_vals);
187 goto out_free_hist_cnt;
189 tl_collect_values_u32(telemetry, ctr->offset2, hist_cnt);
191 for (i = 0; i < sample_cnt; i++) {
192 /* Avoid division by 0 if count is 0. */
194 hist_vals[i] = div_u64(hist_vals[i] * cpp_ns_per_cycle,
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);
212 /* Convert HW raw bandwidth units to Mbps. */
213 static 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)
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;
223 hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals),
228 memset(vals, 0, sizeof(*vals));
229 sample_cnt = tl_collect_values_u32(telemetry, ctr->offset1, hist_vals);
231 goto out_free_hist_vals;
233 vals->curr = div_u64(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);
243 static 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)
247 seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, name);
248 seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->curr);
249 if (atomic_read(&telemetry->state) > 1) {
250 seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->min);
251 seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->max);
252 seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->avg);
257 static int tl_calc_and_print_counter(struct adf_telemetry *telemetry,
259 const struct adf_tl_dbg_counter *ctr,
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;
268 case ADF_TL_SIMPLE_COUNT:
269 ret = tl_calc_count(telemetry, ctr, &vals);
271 case ADF_TL_COUNTER_NS:
272 ret = tl_cycles_to_ns(telemetry, ctr, &vals);
274 case ADF_TL_COUNTER_NS_AVG:
275 ret = tl_lat_acc_avg(telemetry, ctr, &vals);
277 case ADF_TL_COUNTER_MBPS:
278 ret = tl_bw_hw_units_to_mbps(telemetry, ctr, &vals);
287 tl_seq_printf_counter(telemetry, s, counter_name, &vals);
292 static 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)
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];
301 snprintf(cnt_name, MAX_COUNT_NAME_SIZE, "%s%d", ctr->name, cnt_id);
303 slice_ctr.offset1 += offset_inc;
305 return tl_calc_and_print_counter(telemetry, s, &slice_ctr, cnt_name);
308 static int tl_calc_and_print_sl_counters(struct adf_accel_dev *accel_dev,
309 struct seq_file *s, u8 cnt_type, u8 cnt_id)
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;
318 sl_tl_util_counters = tl_data->sl_util_counters;
319 sl_tl_exec_counters = tl_data->sl_exec_counters;
321 ctr = &sl_tl_util_counters[cnt_type];
323 ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id);
325 dev_notice(&GET_DEV(accel_dev),
326 "invalid slice utilization counter type\n");
330 ctr = &sl_tl_exec_counters[cnt_type];
332 ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id);
334 dev_notice(&GET_DEV(accel_dev),
335 "invalid slice execution counter type\n");
342 static void tl_print_msg_cnt(struct seq_file *s, u32 msg_cnt)
344 seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, SNAPSHOT_CNT_MSG);
345 seq_printf(s, "%*u\n", TL_VALUE_MIN_PADDING, msg_cnt);
348 static int tl_print_dev_data(struct adf_accel_dev *accel_dev,
351 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
352 struct adf_telemetry *telemetry = accel_dev->telemetry;
353 const struct adf_tl_dbg_counter *dev_tl_counters;
354 u8 num_dev_counters = tl_data->num_dev_counters;
355 u8 *sl_cnt = (u8 *)&telemetry->slice_cnt;
356 const struct adf_tl_dbg_counter *ctr;
361 if (!atomic_read(&telemetry->state)) {
362 dev_info(&GET_DEV(accel_dev), "not enabled\n");
366 dev_tl_counters = tl_data->dev_counters;
368 tl_print_msg_cnt(s, telemetry->msg_cnt);
370 /* Print device level telemetry. */
371 for (i = 0; i < num_dev_counters; i++) {
372 ctr = &dev_tl_counters[i];
373 ret = tl_calc_and_print_counter(telemetry, s, ctr, NULL);
375 dev_notice(&GET_DEV(accel_dev),
376 "invalid counter type\n");
381 /* Print per slice telemetry. */
382 for (i = 0; i < ADF_TL_SL_CNT_COUNT; i++) {
383 for (j = 0; j < sl_cnt[i]; j++) {
384 ret = tl_calc_and_print_sl_counters(accel_dev, s, i, j);
393 static int tl_dev_data_show(struct seq_file *s, void *unused)
395 struct adf_accel_dev *accel_dev = s->private;
400 return tl_print_dev_data(accel_dev, s);
402 DEFINE_SHOW_ATTRIBUTE(tl_dev_data);
404 static int tl_control_show(struct seq_file *s, void *unused)
406 struct adf_accel_dev *accel_dev = s->private;
411 seq_printf(s, "%d\n", atomic_read(&accel_dev->telemetry->state));
416 static ssize_t tl_control_write(struct file *file, const char __user *userbuf,
417 size_t count, loff_t *ppos)
419 struct seq_file *seq_f = file->private_data;
420 struct adf_accel_dev *accel_dev;
421 struct adf_telemetry *telemetry;
422 struct adf_tl_hw_data *tl_data;
427 accel_dev = seq_f->private;
431 tl_data = &GET_TL_DATA(accel_dev);
432 telemetry = accel_dev->telemetry;
433 dev = &GET_DEV(accel_dev);
435 mutex_lock(&telemetry->wr_lock);
437 ret = kstrtou32_from_user(userbuf, count, 10, &input);
439 goto unlock_and_exit;
441 if (input > tl_data->num_hbuff) {
442 dev_info(dev, "invalid control input\n");
444 goto unlock_and_exit;
447 /* If input is 0, just stop telemetry. */
449 ret = adf_tl_halt(accel_dev);
453 goto unlock_and_exit;
456 /* If TL is already enabled, stop it. */
457 if (atomic_read(&telemetry->state)) {
458 dev_info(dev, "already enabled, restarting.\n");
459 ret = adf_tl_halt(accel_dev);
461 goto unlock_and_exit;
464 ret = adf_tl_run(accel_dev, input);
466 goto unlock_and_exit;
471 mutex_unlock(&telemetry->wr_lock);
474 DEFINE_SHOW_STORE_ATTRIBUTE(tl_control);
476 static int get_rp_index_from_file(const struct file *f, u8 *rp_id, u8 rp_num)
482 ret = sscanf(f->f_path.dentry->d_name.name, ADF_TL_RP_REGS_FNAME, &alpha);
486 index = ADF_TL_DBG_RP_INDEX_ALPHA(alpha);
492 static int adf_tl_dbg_change_rp_index(struct adf_accel_dev *accel_dev,
493 unsigned int new_rp_num,
494 unsigned int rp_regs_index)
496 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
497 struct adf_telemetry *telemetry = accel_dev->telemetry;
498 struct device *dev = &GET_DEV(accel_dev);
503 if (new_rp_num >= hw_data->num_rps) {
504 dev_info(dev, "invalid Ring Pair number selected\n");
508 for (i = 0; i < hw_data->tl_data.max_rp; i++) {
509 if (telemetry->rp_num_indexes[i] == new_rp_num) {
510 dev_info(dev, "RP nr: %d is already selected in slot rp_%c_data\n",
511 new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(i));
516 dev_dbg(dev, "selecting RP nr %u into slot rp_%c_data\n",
517 new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index));
519 curr_state = atomic_read(&telemetry->state);
522 ret = adf_tl_halt(accel_dev);
526 telemetry->rp_num_indexes[rp_regs_index] = new_rp_num;
528 ret = adf_tl_run(accel_dev, curr_state);
532 telemetry->rp_num_indexes[rp_regs_index] = new_rp_num;
538 static void tl_print_rp_srv(struct adf_accel_dev *accel_dev, struct seq_file *s,
541 u32 banks_per_vf = GET_HW_DATA(accel_dev)->num_banks_per_vf;
542 enum adf_cfg_service_type svc;
544 seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, RP_SERVICE_TYPE);
546 svc = GET_SRV_TYPE(accel_dev, rp_idx % banks_per_vf);
549 seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_DC);
552 seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_SYM);
555 seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_ASYM);
558 seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, TL_RP_SRV_UNKNOWN);
563 static int tl_print_rp_data(struct adf_accel_dev *accel_dev, struct seq_file *s,
566 struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
567 struct adf_telemetry *telemetry = accel_dev->telemetry;
568 const struct adf_tl_dbg_counter *rp_tl_counters;
569 u8 num_rp_counters = tl_data->num_rp_counters;
570 size_t rp_regs_sz = tl_data->rp_reg_sz;
571 struct adf_tl_dbg_counter ctr;
576 if (!atomic_read(&telemetry->state)) {
577 dev_info(&GET_DEV(accel_dev), "not enabled\n");
581 rp_tl_counters = tl_data->rp_counters;
582 rp_idx = telemetry->rp_num_indexes[rp_regs_index];
584 if (rp_idx == ADF_TL_RP_REGS_DISABLED) {
585 dev_info(&GET_DEV(accel_dev), "no RP number selected in rp_%c_data\n",
586 ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index));
590 tl_print_msg_cnt(s, telemetry->msg_cnt);
591 seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, RP_NUM_INDEX);
592 seq_printf(s, "%*d\n", TL_VALUE_MIN_PADDING, rp_idx);
593 tl_print_rp_srv(accel_dev, s, rp_idx);
595 for (i = 0; i < num_rp_counters; i++) {
596 ctr = rp_tl_counters[i];
597 ctr.offset1 += rp_regs_sz * rp_regs_index;
598 ctr.offset2 += rp_regs_sz * rp_regs_index;
599 ret = tl_calc_and_print_counter(telemetry, s, &ctr, NULL);
601 dev_dbg(&GET_DEV(accel_dev),
602 "invalid RP counter type\n");
610 static int tl_rp_data_show(struct seq_file *s, void *unused)
612 struct adf_accel_dev *accel_dev = s->private;
620 max_rp = GET_TL_DATA(accel_dev).max_rp;
621 ret = get_rp_index_from_file(s->file, &rp_regs_index, max_rp);
623 dev_dbg(&GET_DEV(accel_dev), "invalid RP data file name\n");
627 return tl_print_rp_data(accel_dev, s, rp_regs_index);
630 static ssize_t tl_rp_data_write(struct file *file, const char __user *userbuf,
631 size_t count, loff_t *ppos)
633 struct seq_file *seq_f = file->private_data;
634 struct adf_accel_dev *accel_dev;
635 struct adf_telemetry *telemetry;
636 unsigned int new_rp_num;
641 accel_dev = seq_f->private;
645 telemetry = accel_dev->telemetry;
646 max_rp = GET_TL_DATA(accel_dev).max_rp;
648 mutex_lock(&telemetry->wr_lock);
650 ret = get_rp_index_from_file(file, &rp_regs_index, max_rp);
652 dev_dbg(&GET_DEV(accel_dev), "invalid RP data file name\n");
653 goto unlock_and_exit;
656 ret = kstrtou32_from_user(userbuf, count, 10, &new_rp_num);
658 goto unlock_and_exit;
660 ret = adf_tl_dbg_change_rp_index(accel_dev, new_rp_num, rp_regs_index);
662 goto unlock_and_exit;
667 mutex_unlock(&telemetry->wr_lock);
670 DEFINE_SHOW_STORE_ATTRIBUTE(tl_rp_data);
672 void adf_tl_dbgfs_add(struct adf_accel_dev *accel_dev)
674 struct adf_telemetry *telemetry = accel_dev->telemetry;
675 struct dentry *parent = accel_dev->debugfs_dir;
676 u8 max_rp = GET_TL_DATA(accel_dev).max_rp;
677 char name[ADF_TL_RP_REGS_FNAME_SIZE];
684 dir = debugfs_create_dir("telemetry", parent);
685 accel_dev->telemetry->dbg_dir = dir;
686 debugfs_create_file("device_data", 0444, dir, accel_dev, &tl_dev_data_fops);
687 debugfs_create_file("control", 0644, dir, accel_dev, &tl_control_fops);
689 for (i = 0; i < max_rp; i++) {
690 snprintf(name, sizeof(name), ADF_TL_RP_REGS_FNAME,
691 ADF_TL_DBG_RP_ALPHA_INDEX(i));
692 debugfs_create_file(name, 0644, dir, accel_dev, &tl_rp_data_fops);
696 void adf_tl_dbgfs_rm(struct adf_accel_dev *accel_dev)
698 struct adf_telemetry *telemetry = accel_dev->telemetry;
699 struct dentry *dbg_dir;
704 dbg_dir = telemetry->dbg_dir;
706 debugfs_remove_recursive(dbg_dir);
708 if (atomic_read(&telemetry->state))
709 adf_tl_halt(accel_dev);